# Laradock - Full Documentation > A full PHP development environment for Docker. All documentation pages concatenated for AI agents. Source: https://github.com/laradock/laradock Tip: append `.md` to any page URL (e.g. https://laradock.io/docs/getting-started.md) to fetch that single page's raw Markdown. ================================================================ # Introduction Source: https://laradock.io/docs/Intro ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import TerminalDemo from '@site/src/components/TerminalDemo'; import { GoalBar } from '@site/src/components/SupportBanner';

The easiest way to run PHP on Docker.

**Laradock is a complete Docker environment for PHP.** Clone it into any PHP project, run one command, and you have a complete local stack running. ![Laradock - full PHP development environment based on Docker](https://laradock.io/img/laradock/laradock-logo.png) It ships pre-configured containers for everything a PHP application needs: a web server ([Nginx](https://laradock.io/docs/services/nginx)), the PHP runtime ([PHP-FPM](https://laradock.io/docs/services/php-fpm)), a database ([MySQL](https://laradock.io/docs/services/mysql)), caching ([Redis](https://laradock.io/docs/services/redis)), background jobs ([PHP Worker](https://laradock.io/docs/services/php-worker)), search ([Elasticsearch](https://laradock.io/docs/services/elasticsearch)), mail testing ([Mailpit](https://laradock.io/docs/services/mailpit)), and [100+ additional services](#supported-services), all ready to use with zero manual configuration. Whether you're using the built-in [Laradock CLI](https://laradock.io/docs/cli), no Docker knowledge required, or plain `docker compose` when you want full control, the same stack works with **any PHP project**, including [Laravel](https://laradock.io/docs/laravel-on-docker), [WordPress](https://laradock.io/docs/wordpress-on-docker), [Symfony](https://laradock.io/docs/symfony-on-docker), [Drupal](https://laradock.io/docs/drupal-on-docker), [Magento](https://laradock.io/docs/magento-on-docker), [100+ other](https://laradock.io/docs/supported-php-projects) frameworks and applications, or plain PHP. Every developer gets the same environment on Linux, macOS, and Windows, eliminating setup differences and "works on my machine" problems. Laradock doesn't stop at local development. Built-in production deployment with [`./laradock ship`](https://laradock.io/docs/production) packages your application and deploys it to [Kubernetes](https://laradock.io/docs/deploy-to-kubernetes), [Google Cloud Run](https://laradock.io/docs/deploy-to-google-cloud-run), [AWS ECS](https://laradock.io/docs/deploy-to-aws-ecs), [your own server](https://laradock.io/docs/deploy-to-a-server), and [many more](https://laradock.io/docs/production), without switching tools or rebuilding your environment. Trusted by 100K+ developers, it's free and open-source under the MIT license, and has been battle-tested in real-world PHP projects since 2015.
Already running an older version of Laradock?
Upgrade straight to the latest, with AI, in one go. It's safe, nothing you already run changes.
πŸ€– Upgrade with AI Upgrade Guide β†’
> **Use Docker first. Learn about it later.**


{/* SYNC: keep this tip identical in docs/Intro.md and docs/getting-started.md */} :::tip[Let AI use it] Three ways to point your AI assistant at Laradock: - **Run it for you** - the repo ships agent instructions ([`AGENTS.md`](https://github.com/laradock/laradock/blob/master/AGENTS.md) + rule files for [Claude Code](https://claude.com/claude-code), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor](https://cursor.com), [Cline](https://cline.bot), and [Windsurf](https://windsurf.com)). Open the repo in your agent and say *"Set up Laradock for this project."* - **Ask about it, no clone** - add the docs as an MCP server: `https://gitmcp.io/laradock/laradock`. - **Read a walkthrough** - browse the AI-generated overview on [DeepWiki](https://deepwiki.com/laradock/laradock), starting with its [architecture diagram](https://deepwiki.com/laradock/laradock/1-overview-of-laradock#system-architecture). ::: ## Quick Start Requires Docker with Compose v2.20+. Pick a tab, both reach the exact same result, and you can switch any time. 1 - Clone Laradock inside your PHP project: ```shell git clone https://github.com/Laradock/laradock.git ``` 2 - Enter the laradock folder: ```shell cd laradock ``` 3 - Start your stack: ```shell ./laradock start ``` The first time, `start` runs a short setup wizard, then launches your stack. Full walkthrough and all options: [Getting Started](https://laradock.io/docs/getting-started#get-started). 4 - Enter the Laradock Workspace (a dev shell with `php`, `composer`, `node`, and `git` inside): ```shell ./laradock workspace ``` Then open `http://localhost`. Done. The CLI is optional, transparent sugar: it prints every `docker compose` command it runs, keeps no state, and writes nothing but your `.env`. Full reference: [The Laradock CLI](https://laradock.io/docs/cli). The same result, step by step, with you in charge of every detail: 1 - Clone Laradock inside your PHP project: ```shell git clone https://github.com/Laradock/laradock.git ``` 2 - Enter the laradock folder and rename `.env.example` to `.env`. ```shell cp .env.example .env ``` 3 - Run your containers: ```shell docker compose up -d workspace nginx mysql redis ``` 4 - Open your project's `.env` file and set the following: ```shell DB_HOST=mysql REDIS_HOST=redis QUEUE_HOST=beanstalkd ``` 5 - Open your browser and visit localhost: `http://localhost`. Done.
Full Getting Started Guide See How It Works Usage and Commands
## What's New (2026) Battle-tested since 2015, and still growing. Recent highlights: - **Deploy to production**, [`./laradock ship`](https://laradock.io/docs/production) builds an image for any server or cloud. - **A plain-English CLI**, [`./laradock start`](https://laradock.io/docs/cli) runs your whole stack, no Docker needed. - **Local AI built in**, run LLMs and vector databases on your own machine. - **100+ services ready**, plus every PHP version from 5.6 to 8.5. See the [release notes](https://github.com/laradock/laradock/releases) for the full history. Already on an older version? Jumping straight to the latest is safe, nothing you run changes. See the **[Upgrade Guide](https://laradock.io/docs/upgrade-guide)** for the one structural change to know about. ## Features - **Any PHP Version**: Run any version from 5.6 to 8.5. Set `PHP_VERSION` in `.env`, rebuild, and you're on it. - **100+ Ready-made Services**: Databases, caches, queues, search engines, and more, pre-configured and waiting. - **All-in-One Dev Shell**: Run Artisan, Composer, Node, and any CLI inside the `workspace` container, nothing on host. - **Deploy to Production**: Turn your stack into a hardened image with `./laradock ship`, then deploy anywhere. - **Pick Your Database**: MySQL, PostgreSQL, MariaDB, MongoDB, Redis, and many others, ready to switch on. - **Framework-Agnostic**: Works with Laravel, Symfony, WordPress, Magento, Drupal, or plain PHP. - **Local AI, Built In**: Run LLMs and vector search locally with Ollama, LiteLLM, pgvector, Qdrant, no cloud bills. - **Toggle Services On Demand**: Start only what a project needs with `docker compose up`, and stop them easily. - **One Environment Everywhere**: Identical setup on Linux, macOS, and Windows, so your team shares the stack. - **A Container Per Service**: Every service is isolated, so nothing conflicts and each piece is easy to manage. - **Configure From One File**: Every service ships pre-configured; override any setting with 1 line in `.env`, always wins. - **Official Base Images**: Every image builds on a trusted upstream source for reliability and security. - **Web Server Ready**: NGINX, Apache, and Caddy come pre-configured to serve your code out of the box. - **One or Many Projects**: Run a dedicated Laradock per project, or share a single setup across all of them. - **Yours to Edit**: Every `Dockerfile` and config is plain, readable, and open for you to change. ## Supported PHP Projects Laradock provides the PHP runtime, web server, databases, and background services your app needs, so it runs virtually any PHP framework, CMS, or e-commerce platform, right down to plain framework-free PHP. New here? Jump straight to a step-by-step guide for the most popular platforms:
Laravel WordPress Symfony Drupal Magento WooCommerce Moodle CodeIgniter Nextcloud PrestaShop
Not listed? Pick from the full catalog of 100+ supported projects below. | Type | Projects | |------|----------| | **Frameworks** | [Laravel](https://laradock.io/docs/laravel-on-docker), [Symfony](https://laradock.io/docs/symfony-on-docker), [CodeIgniter](https://laradock.io/docs/codeigniter-on-docker), [Yii](https://laradock.io/docs/yii-on-docker), [Laminas (Zend Framework)](https://laradock.io/docs/laminas-on-docker), [CakePHP](https://laradock.io/docs/cakephp-on-docker), [Phalcon](https://laradock.io/docs/phalcon-on-docker), [Slim](https://laradock.io/docs/slim-on-docker), [Lumen](https://laradock.io/docs/lumen-on-docker), [FuelPHP](https://laradock.io/docs/fuelphp-on-docker), [Spiral](https://laradock.io/docs/spiral-on-docker), [Hyperf](https://laradock.io/docs/hyperf-on-docker), [API Platform](https://laradock.io/docs/api-platform-on-docker), [Mezzio](https://laradock.io/docs/mezzio-on-docker), [Flight](https://laradock.io/docs/flight-on-docker), [Fat-Free Framework (F3)](https://laradock.io/docs/fat-free-framework-on-docker), [ThinkPHP](https://laradock.io/docs/thinkphp-on-docker), [Silex](https://laradock.io/docs/silex-on-docker), [Swoole](https://laradock.io/docs/swoole-on-docker), [Workerman](https://laradock.io/docs/workerman-on-docker), [Ubiquity](https://laradock.io/docs/ubiquity-on-docker), [SilverStripe](https://laradock.io/docs/silverstripe-on-docker), [Nette](https://laradock.io/docs/nette-on-docker), [Leaf PHP](https://laradock.io/docs/leaf-php-on-docker) | | **CMS** | [WordPress](https://laradock.io/docs/wordpress-on-docker), [Drupal](https://laradock.io/docs/drupal-on-docker), [Joomla](https://laradock.io/docs/joomla-on-docker), [October CMS](https://laradock.io/docs/october-cms-on-docker), [Statamic](https://laradock.io/docs/statamic-on-docker), [Craft CMS](https://laradock.io/docs/craft-cms-on-docker), [TYPO3](https://laradock.io/docs/typo3-on-docker), [Concrete CMS](https://laradock.io/docs/concrete-cms-on-docker), [Grav](https://laradock.io/docs/grav-on-docker), [Backdrop CMS](https://laradock.io/docs/backdrop-cms-on-docker), [HTMLy](https://laradock.io/docs/htmly-on-docker), [Kirby](https://laradock.io/docs/kirby-on-docker), [ProcessWire](https://laradock.io/docs/processwire-on-docker), [Pico](https://laradock.io/docs/pico-on-docker), [Bolt CMS](https://laradock.io/docs/bolt-cms-on-docker), [Contao](https://laradock.io/docs/contao-on-docker), [b2evolution](https://laradock.io/docs/b2evolution-on-docker), [Serendipity](https://laradock.io/docs/serendipity-on-docker), [Nucleus](https://laradock.io/docs/nucleus-cms-on-docker), [e107](https://laradock.io/docs/e107-on-docker), [Pligg](https://laradock.io/docs/pligg-on-docker), [Sulu CMS](https://laradock.io/docs/sulu-cms-on-docker), [Pimcore](https://laradock.io/docs/pimcore-on-docker), [Winter CMS](https://laradock.io/docs/winter-cms-on-docker), [Neos CMS](https://laradock.io/docs/neos-cms-on-docker), [Textpattern](https://laradock.io/docs/textpattern-on-docker), [ExpressionEngine](https://laradock.io/docs/expressionengine-on-docker) | | **E-commerce** | [Magento](https://laradock.io/docs/magento-on-docker), [WooCommerce](https://laradock.io/docs/woocommerce-on-docker), [PrestaShop](https://laradock.io/docs/prestashop-on-docker), [OpenCart](https://laradock.io/docs/opencart-on-docker), [Sylius](https://laradock.io/docs/sylius-on-docker), [Bagisto](https://laradock.io/docs/bagisto-on-docker), [Aimeos](https://laradock.io/docs/aimeos-on-docker), [Avored](https://laradock.io/docs/avored-on-docker), [OroCommerce](https://laradock.io/docs/orocommerce-on-docker), [Zen Cart](https://laradock.io/docs/zen-cart-on-docker), [osCommerce](https://laradock.io/docs/oscommerce-on-docker), [AbanteCart](https://laradock.io/docs/abantecart-on-docker), [CubeCart](https://laradock.io/docs/cubecart-on-docker), [Shopware](https://laradock.io/docs/shopware-on-docker), [LiteCart](https://laradock.io/docs/litecart-on-docker), [OpenMage](https://laradock.io/docs/openmage-on-docker) | | **Apps** | [Moodle](https://laradock.io/docs/moodle-on-docker), [MediaWiki](https://laradock.io/docs/mediawiki-on-docker), [phpBB](https://laradock.io/docs/phpbb-on-docker), [Matomo](https://laradock.io/docs/matomo-on-docker), [MyBB](https://laradock.io/docs/mybb-on-docker), [FluxBB](https://laradock.io/docs/fluxbb-on-docker), [PunBB](https://laradock.io/docs/punbb-on-docker), [Flarum](https://laradock.io/docs/flarum-on-docker), [bbPress](https://laradock.io/docs/bbpress-on-docker), [Simple Machines Forum (SMF)](https://laradock.io/docs/smf-on-docker), [DokuWiki](https://laradock.io/docs/dokuwiki-on-docker), [BookStack](https://laradock.io/docs/bookstack-on-docker), [Roundcube](https://laradock.io/docs/roundcube-on-docker), [phpMyAdmin](https://laradock.io/docs/phpmyadmin-on-docker), [Adminer](https://laradock.io/docs/adminer-on-docker), [SuiteCRM](https://laradock.io/docs/suitecrm-on-docker), [EspoCRM](https://laradock.io/docs/espocrm-on-docker), [Vtiger](https://laradock.io/docs/vtiger-on-docker), [Dolibarr](https://laradock.io/docs/dolibarr-on-docker), [Aureus ERP](https://laradock.io/docs/aureus-erp-on-docker), [WebERP](https://laradock.io/docs/weberp-on-docker), [FrontAccounting](https://laradock.io/docs/frontaccounting-on-docker), [Kanboard](https://laradock.io/docs/kanboard-on-docker), [Firefly III](https://laradock.io/docs/firefly-iii-on-docker), [Invoice Ninja](https://laradock.io/docs/invoice-ninja-on-docker), [X2CRM](https://laradock.io/docs/x2crm-on-docker), [Nextcloud](https://laradock.io/docs/nextcloud-on-docker), [ownCloud](https://laradock.io/docs/owncloud-on-docker), [Pydio](https://laradock.io/docs/pydio-on-docker), [Mautic](https://laradock.io/docs/mautic-on-docker), [Crater](https://laradock.io/docs/crater-on-docker), [Akaunting](https://laradock.io/docs/akaunting-on-docker), [Monica CRM](https://laradock.io/docs/monica-crm-on-docker), [Leantime](https://laradock.io/docs/leantime-on-docker), [Cachet](https://laradock.io/docs/cachet-on-docker), [PHP Server Monitor](https://laradock.io/docs/php-server-monitor-on-docker), [YOURLS](https://laradock.io/docs/yourls-on-docker), [LinkAce](https://laradock.io/docs/linkace-on-docker), [Koel](https://laradock.io/docs/koel-on-docker), [AzuraCast](https://laradock.io/docs/azuracast-on-docker), [Lychee](https://laradock.io/docs/lychee-on-docker), [Vanilla Forums](https://laradock.io/docs/vanilla-forums-on-docker) | ## Supported Services A **service** is one piece of software, a database, a web server, a cache, a queue, that Laradock runs for you in its own isolated **container** (a lightweight, self-contained box). Each one is already configured, so you just switch on the ones your project needs and leave the rest off. Because they're isolated, they never conflict with each other or with anything on your machine. To start any service from the list below, use its name, which is the same as its folder name. For example, the "PHP FPM" service lives in the `php-fpm` folder, so you start it with `php-fpm`: ```bash ./laradock start php-fpm ``` ```bash docker compose up -d php-fpm ``` | Category | Services (Containers) | |---------------------------|--------------------------------------------------------------------------| | (**Laradock Workspace**) | [PHP CLI](https://laradock.io/docs/services/workspace), [Composer](https://laradock.io/docs/services/workspace), [Git](https://laradock.io/docs/services/workspace), [Vim](https://laradock.io/docs/services/workspace), [xDebug](https://laradock.io/docs/services/workspace), [Linuxbrew](https://laradock.io/docs/services/workspace), [Node](https://laradock.io/docs/services/workspace), [V8JS](https://laradock.io/docs/services/workspace), [Gulp](https://laradock.io/docs/services/workspace), [SQLite](https://laradock.io/docs/services/workspace), [Laravel Envoy](https://laradock.io/docs/services/workspace), [Deployer](https://laradock.io/docs/services/workspace), [Yarn](https://laradock.io/docs/services/workspace), [SOAP](https://laradock.io/docs/services/workspace), [Drush](https://laradock.io/docs/services/workspace), [Wordpress CLI](https://laradock.io/docs/services/workspace), [dnsutils](https://laradock.io/docs/services/workspace), [Terraform](https://laradock.io/docs/services/workspace), [ImageMagick](https://laradock.io/docs/services/workspace), [Drupal Console](https://laradock.io/docs/services/workspace), [Protoc](https://laradock.io/docs/services/workspace), [JDK](https://laradock.io/docs/services/workspace), [Docker Client](https://laradock.io/docs/services/workspace) | | **Web Servers** | [NGINX](https://laradock.io/docs/services/nginx), [Apache2](https://laradock.io/docs/services/apache2), [Caddy](https://laradock.io/docs/services/caddy), [OpenResty](https://laradock.io/docs/services/openresty), [Tomcat](https://laradock.io/docs/services/tomcat), [FrankenPHP](https://laradock.io/docs/services/frankenphp) | | **Load Balancers** | [HAProxy](https://laradock.io/docs/services/haproxy), [Traefik](https://laradock.io/docs/services/traefik) | | **PHP Compilers** | [PHP FPM](https://laradock.io/docs/services/php-fpm), [RoadRunner](https://laradock.io/docs/services/roadrunner) | | **Database Management Systems** | [MySQL](https://laradock.io/docs/services/mysql), [PostgreSQL](https://laradock.io/docs/services/postgres), [PostGIS](https://laradock.io/docs/services/postgres-postgis), [pgvector](https://laradock.io/docs/services/pgvector), [MariaDB](https://laradock.io/docs/services/mariadb), [Percona](https://laradock.io/docs/services/percona), [MSSQL](https://laradock.io/docs/services/mssql), [MongoDB](https://laradock.io/docs/services/mongo), [Neo4j](https://laradock.io/docs/services/neo4j), [CouchDB](https://laradock.io/docs/services/couchdb), [RethinkDB](https://laradock.io/docs/services/rethinkdb), [Cassandra](https://laradock.io/docs/services/cassandra), [ClickHouse](https://laradock.io/docs/services/clickhouse), [Tarantool](https://laradock.io/docs/services/tarantool) | | **Database Management Tools** | [PhpMyAdmin](https://laradock.io/docs/services/phpmyadmin), [Adminer](https://laradock.io/docs/services/adminer), [PgAdmin](https://laradock.io/docs/services/pgadmin), [MongoDB Web UI](https://laradock.io/docs/services/mongo-webui), [Tarantool Admin](https://laradock.io/docs/services/tarantool-admin), [pgbackups (PostgreSQL)](https://laradock.io/docs/services/pgbackups) | | **Cache Engines** | [Redis](https://laradock.io/docs/services/redis), [Redis Web UI](https://laradock.io/docs/services/redis-webui), [Redis Cluster](https://laradock.io/docs/services/redis-cluster), [Valkey](https://laradock.io/docs/services/valkey), [Dragonfly](https://laradock.io/docs/services/dragonfly), [Memcached](https://laradock.io/docs/services/memcached), [Aerospike](https://laradock.io/docs/services/aerospike), [Varnish](https://laradock.io/docs/services/varnish), [SSDB](https://laradock.io/docs/services/ssdb) | | **Message Brokers** | [RabbitMQ](https://laradock.io/docs/services/rabbitmq), [RabbitMQ Admin Console](https://laradock.io/docs/services/rabbitmq), [Beanstalkd](https://laradock.io/docs/services/beanstalkd), [Beanstalkd Admin Console](https://laradock.io/docs/services/beanstalkd-console), [Eclipse Mosquitto](https://laradock.io/docs/services/mosquitto), [Gearman](https://laradock.io/docs/services/gearman), [NATS](https://laradock.io/docs/services/nats), [Apache Kafka](https://laradock.io/docs/services/kafka), [Kafka Manager](https://laradock.io/docs/services/kafka-manager) | | **Log Management** | [GrayLog](https://laradock.io/docs/services/graylog), [Kibana](https://laradock.io/docs/services/kibana), [LogStash](https://laradock.io/docs/services/logstash) | | **Search Engines** | [ElasticSearch](https://laradock.io/docs/services/elasticsearch), [OpenSearch](https://laradock.io/docs/services/opensearch), [Apache Solr](https://laradock.io/docs/services/solr), [Manticore Search](https://laradock.io/docs/services/manticore), [Typesense](https://laradock.io/docs/services/typesense), [Meilisearch](https://laradock.io/docs/services/meilisearch), [Dejavu](https://laradock.io/docs/services/dejavu) | | **Vector Databases** | [pgvector](https://laradock.io/docs/services/pgvector), [Qdrant](https://laradock.io/docs/services/qdrant), [Weaviate](https://laradock.io/docs/services/weaviate), [Chroma](https://laradock.io/docs/services/chroma) | | **Graph / Multi-model Databases** | [Neo4j](https://laradock.io/docs/services/neo4j), [ArangoDB](https://laradock.io/docs/services/arangodb), [SurrealDB](https://laradock.io/docs/services/surrealdb) | | **Time-series Databases** | [InfluxDB](https://laradock.io/docs/services/influxdb) | | **AI / LLM** | [Ollama](https://laradock.io/docs/services/ollama), [vLLM](https://laradock.io/docs/services/vllm), [LocalAI](https://laradock.io/docs/services/localai), [LiteLLM](https://laradock.io/docs/services/litellm), [Open WebUI](https://laradock.io/docs/services/open-webui), [MCP](https://laradock.io/docs/services/mcp) | | **Agentic / Automation** | [n8n](https://laradock.io/docs/services/n8n), [Flowise](https://laradock.io/docs/services/flowise), [Langflow](https://laradock.io/docs/services/langflow) | | **PHP Extensions** | [Swoole](https://laradock.io/docs/swoole-on-docker), [Blackfire](https://laradock.io/docs/services/blackfire), [Phalcon](https://laradock.io/docs/phalcon-on-docker), [PHP Worker](https://laradock.io/docs/services/php-worker), [Laravel Horizon](https://laradock.io/docs/services/laravel-horizon) | | **Mail Servers** | [Mailu](https://laradock.io/docs/services/mailu), [MailCatcher](https://laradock.io/docs/services/mailcatcher), [Mailhog](https://laradock.io/docs/services/mailhog), [MailDev](https://laradock.io/docs/services/maildev), [Mailpit](https://laradock.io/docs/services/mailpit) | | **Real-time Communication** | [Laravel Echo](https://laradock.io/docs/services/laravel-echo-server), [Laravel Reverb](https://laradock.io/docs/services/laravel-reverb), [Mercure](https://laradock.io/docs/services/mercure), [Soketi](https://laradock.io/docs/services/soketi) | | **Monitoring** | [Grafana](https://laradock.io/docs/services/grafana), [NetData](https://laradock.io/docs/services/netdata), [Prometheus](https://laradock.io/docs/services/prometheus) | | **Coordination Services** | [Apache ZooKeeper](https://laradock.io/docs/services/zookeeper) | | **Container Management** | [Portainer](https://laradock.io/docs/services/portainer), [Docker Registry](https://laradock.io/docs/services/docker-registry) | | **CI/CD Tools** | [Jenkins](https://laradock.io/docs/services/jenkins), [SonarQube](https://laradock.io/docs/services/sonarqube), [Gitlab](https://laradock.io/docs/services/gitlab), [GitLab Runner](https://laradock.io/docs/services/gitlab-runner), [OneDev](https://laradock.io/docs/services/onedev) | | **Cloud Tools** | [AWS EB CLI](https://laradock.io/docs/services/aws-eb-cli), [Amazon Simple Queue Service](https://laradock.io/docs/services/sqs) | | **Image Processing** | [Thumbor](https://laradock.io/docs/services/thumbor) | | **Security & Identity Tools** | [Certbot](https://laradock.io/docs/services/certbot), [Keycloak](https://laradock.io/docs/services/keycloak) | | **Object Storage** | [Minio](https://laradock.io/docs/services/minio) | | **Testing** | [Selenium](https://laradock.io/docs/services/selenium) | | **IDEs** | [Theia](https://laradock.io/docs/services/ide-theia) | | **API Documentation** | [Swagger UI](https://laradock.io/docs/services/swagger-ui), [Swagger Editor](https://laradock.io/docs/services/swagger-editor) | | **Analytics / BI** | [Metabase](https://laradock.io/docs/services/metabase) | | **Collaboration** | [Confluence](https://laradock.io/docs/services/confluence) | You can choose which tools to install in your workspace container and other containers: browse the available flags in each container's `defaults.env` (e.g. `workspace/defaults.env`), then set the ones you want in your `.env` (your `.env` overrides all defaults). *If you modify a `compose.yml`, `defaults.env`, `.env` or any `dockerfile` file, you must re-build your containers, to see those effects in the running instance.* :::tip If you can't find your Software in the list, build it yourself and submit it. Contributions are welcomed :) ::: --- ## Deploy Anywhere Laradock follows your app to production. Build one image with `./laradock ship`, then run that same image on any of these: | Where | Platforms | |-------|-----------| | **Managed clouds** | [Google Cloud Run](https://laradock.io/docs/deploy-to-google-cloud-run) Β· [AWS ECS](https://laradock.io/docs/deploy-to-aws-ecs) Β· [AWS App Runner](https://laradock.io/docs/deploy-to-aws-app-runner) Β· [Azure Container Apps](https://laradock.io/docs/deploy-to-azure-container-apps) Β· [Fly.io](https://laradock.io/docs/deploy-to-fly-io) Β· [Render](https://laradock.io/docs/deploy-to-render) Β· [Railway](https://laradock.io/docs/deploy-to-railway) Β· [DigitalOcean](https://laradock.io/docs/deploy-to-digitalocean) Β· [Heroku](https://laradock.io/docs/deploy-to-heroku) | | **Your own infrastructure** | [Kubernetes](https://laradock.io/docs/deploy-to-kubernetes) Β· [Kamal](https://laradock.io/docs/deploy-to-kamal) Β· [A single server](https://laradock.io/docs/deploy-to-a-server) | Start here: [Deploy to Production](https://laradock.io/docs/production). ## Your All-in-One Dev Workspace Laradock ships a **Workspace**: a ready-to-use Linux command line with PHP, Composer, Node, Git, and dozens of dev tools already installed. You run every command your project needs *inside* it, so nothing gets installed on your own machine. Enter it and work from there: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` `artisan`, `composer`, `phpunit`, `npm`, and `git` all just work, with nothing installed on your host: no PHP, no Composer, no Node, no version conflicts. Stop the project and **zero traces are left on your device.** Why it's a big deal: - **Start in seconds.** Every tool is already installed and configured, so there's nothing to set up; clone a project and get to work. - **Keep your machine spotless.** Run everything inside the container; your host never gets PHP, Composer, Node, or any CLI, and nothing is left behind when you're done. - **Isolate every project.** Each one runs on its own PHP and database versions with no conflicts between them. - **Revive old projects.** Run legacy apps on older PHP (5.6, 7.x) without touching your system's PHP version. :::tip[The full journey, from local dev to production] Laradock doesn't stop at your laptop. When your app is ready, `./laradock ship` turns this exact stack into a hardened image you can deploy anywhere, a single server, Kubernetes (EKS/GKE/AKS), or a managed cloud like AWS ECS, Cloud Run, or Fly. Read more: [Deploy to Production](https://laradock.io/docs/production). ::: :::info[How it's organized] One folder per service; each holds that service's `compose.yml` (container definition), `defaults.env` (pre-filled settings), and `Dockerfile`. Change any setting by adding one line to your `.env`, it always wins. Full map in [Getting Started](https://laradock.io/docs/getting-started). Going deeper? [Customizing Images](https://laradock.io/docs/customizing-images) covers changing what's inside a container, and [Data & Volumes](https://laradock.io/docs/volumes) covers where your data lives. ::: ## The Story: Laravel + Docker = Laradock Laradock started in 2015 as exactly what the name says: **Lara**vel + **Dock**er, back when Laravel had no official Docker answer of its own. Then developers wanted more: more databases, caches, queues, search engines, and projects that were never Laravel at all ([Symfony](https://laradock.io/docs/symfony-on-docker), [WordPress](https://laradock.io/docs/wordpress-on-docker), [Magento](https://laradock.io/docs/magento-on-docker), [plain PHP](https://laradock.io/docs/getting-started)). So Laradock grew with them, from one Laravel stack into [100+ pre-configured services](https://laradock.io/docs/supported-services) for [any PHP project](https://laradock.io/docs/supported-php-projects), and now all the way to production with `./laradock ship`. Laravel later shipped its own [Sail](https://laradock.io/docs/laradock-vs-laravel-sail), deliberately small and Laravel-only; Laradock covers the ground it doesn't. ## How Laradock Compares {#laradock-alternatives} Every other option either installs software on your machine (XAMPP, MAMP, Herd) or puts a tool between you and Docker (DDEV, Lando, Sail). Laradock does neither: **it is raw Docker with the wiring already done.** Nothing to install, no new commands to learn, nothing generated or hidden; you use `docker compose` directly on plain, readable files you fully own. That makes it the lightest option to adopt and the easiest one to inspect, debug, and bend to your will. And today it goes further than any of them combine: you pick the services you want and they come wired together, no setup of your own, with a [`workspace`](https://laradock.io/docs/services/workspace) shell that already has every PHP tool in it; [`./laradock ship`](https://laradock.io/docs/production) carries this exact environment to production; a local AI stack ([Ollama](https://laradock.io/docs/services/ollama), [LiteLLM](https://laradock.io/docs/services/litellm), [Qdrant](https://laradock.io/docs/services/qdrant)) is one command away; and an [AI agent can set it up for you](https://github.com/laradock/laradock/blob/master/AGENTS.md) (`AGENTS.md` + [`llms.txt`](https://laradock.io/llms.txt)). Each rival wins on a single axis (Herd on native speed, DDEV on automatic HTTPS); Laradock wins on the combination. See the full honest breakdown, including when the other tools are the better choice: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** (DDEV, Sail, Herd, Lando, XAMPP, and more). ## Community Gitter's done. Our community of 2,000+ active members has a new home on [GitHub Discussions](https://github.com/laradock/laradock/discussions). None of this happens on its own. Behind every container, every fix, and every new service added is someone who cared enough to give their time. Meet the people who make Laradock possible. ## Awesome People Laradock is an MIT-licensed open source project with its ongoing development made possible entirely by the support of you and all these awesome people. πŸ’œ ### Project Maintainers {/* SYNC: keep this list identical to the "Project Maintainers" table in /README.md. Order = number of commits, DESCENDING, EXCEPT @mahmoudz is always pinned first (project founder). Add/remove a maintainer = update BOTH files. */}

Mahmoud Zalt
@mahmoudz

Yu-Lung Shao (Allen)
@bestlong

Winfried van Loon
@winfried-van-loon

Bo-Yi Wu
@appleboy

Valentino Lauciani
@vlauciani

Arian Acosta
@arianacosta

Erik
@erikn69

Dwi Fahni Denni
@zeroc0d3

Dawid Makowski
@makowskid

Luciano Jr
@iamlucianojr

Pavel Savushkin
@PavelSavushkinMix

Philippe TrΓ©panier
@philtrep

Ahkui
@ahkui

Mike Erickson
@mikeerickson

Lan Phan
@lanphan

zhushaolong
@zhushaolong

Frank Yuan
@kideny

xiagw
@xiagw

Abdelrahman Omran
@Omranic

TJ Miller
@sixlive

Thor Erik
@thorerik

Milan Urukalo
@urukalo

Vince Chu
@vwchu

Huadong Zuo
@zuohuadong

< Join Us >
@laradock
### Code Contributors [![Laradock Contributors](https://contrib.rocks/image?repo=laradock/laradock)](https://github.com/laradock/laradock/graphs/contributors) ### Financial Contributors (Backers) [![Open Collective backers](https://opencollective.com/laradock/tiers/awesome-backers.svg?width=800&avatarHeight=55&button=false&isActive=false)](https://opencollective.com/laradock#contributors) --- ## Sponsors **Laradock has stayed free and maintained for 10+ years, funded entirely by the developers who use it.** Here's this month's progress toward keeping it alive: Laradock powers local development for developers and companies worldwide: 100K+ active developers, 5M+ downloads, 100+ services, kept working for 10+ years. Like every open-source project, its future depends on the people who rely on it. Your sponsorship directly funds the maintenance that keeps every service working with the latest PHP, database, and framework versions. **Your team runs on Laradock? Help fund it:** - **Individuals** [sponsor monthly on GitHub](https://github.com/sponsors/laradock), from the price of a coffee. - **Companies** get your logo below with a real dofollow backlink. - **Pay by invoice or bank transfer** if a sponsor button won't clear your finance team: [Open Collective](https://opencollective.com/laradock) issues invoices and takes bank transfers so your organization can pay Laradock directly. [**❀️ Sponsor on GitHub**](https://github.com/sponsors/laradock) · [**Sponsor / invoice via Open Collective**](https://opencollective.com/laradock) · custom or annual agreements: **mahmoud@zalt.me** ### Diamond Sponsors
Sistava - Hire AI Employees to Run Your Business. Apiato - A powerful PHP framework for building scalable, enterprise-grade APIs! {/* Diamond auto-slots: paid Diamond sponsors auto-populate from Open Collective (dofollow, largest logo); empty slots hide themselves. Same mechanism as Gold. */} { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} />
### Gold Sponsors
{ if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} /> { if (e.target.naturalWidth <= 1) e.target.parentNode.style.display = "none"; }} />
### Silver Sponsors
Sista AI - AI Workforce platform. Silver Sponsors
### Bronze Sponsors Bronze Sponsors ### Sponsorship Support Sponsoring is an act of giving in a unique way. 🌱 You can support us using any of the methods below: **1:** [Open Collective](https://opencollective.com/laradock) *Available for all tiers:* Gold, Silver, Bronze, and Backers (Financial Contributors). **Preferred method.** **2:** [GitHub Sponsors](https://github.com/sponsors/Mahmoudz) *Supports the creator of the project directly:* Ideal for personal support of the project creator. ## License [MIT](https://github.com/laradock/laradock/blob/master/LICENSE) © [Mahmoud Zalt](https://zalt.me/) ================================================================ # Getting Started Source: https://laradock.io/docs/getting-started ================================================================ This guide gets Laradock running for your project. The fastest path is the **Laradock CLI**, a short wizard that sets everything up for you, so start there. If you would rather wire things up by hand with plain `docker compose`, see [Manual setup](https://laradock.io/docs/manual-setup), it is meant for advanced users who want full control. {/* SYNC: keep this tip identical in docs/Intro.md and docs/getting-started.md */} :::tip[Let AI use it] Three ways to point your AI assistant at Laradock: - **Run it for you** - the repo ships agent instructions ([`AGENTS.md`](https://github.com/laradock/laradock/blob/master/AGENTS.md) + rule files for [Claude Code](https://claude.com/claude-code), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor](https://cursor.com), [Cline](https://cline.bot), and [Windsurf](https://windsurf.com)). Open the repo in your agent and say *"Set up Laradock for this project."* - **Ask about it, no clone** - add the docs as an MCP server: `https://gitmcp.io/laradock/laradock`. - **Read a walkthrough** - browse the AI-generated overview on [DeepWiki](https://deepwiki.com/laradock/laradock), starting with its [architecture diagram](https://deepwiki.com/laradock/laradock/1-overview-of-laradock#system-architecture). ::: **Building something specific?** Jump straight to a guide tailored to the most popular platforms:
Laravel WordPress Symfony Drupal Magento WooCommerce Moodle CodeIgniter Nextcloud PrestaShop
Not one of these? Browse the [full list of 100+ supported projects](https://laradock.io/docs/Intro#supported-php-projects), then follow its guide. Otherwise the generic steps below work for any PHP app. ## Requirements - [Git](https://git-scm.com/downloads) - [Docker](https://www.docker.com/products/docker-desktop/) (with Docker Compose v2.20 or newer) ## Get started with CLI {#get-started} 1 - Clone Laradock inside your PHP project (or anywhere, if you don't have one yet): ```bash git clone https://github.com/laradock/laradock.git cd laradock ``` 2 - Start your stack: ```bash ./laradock start ``` On the **first run**, `start` walks you through a short setup wizard: it detects your framework and lets you pick your project, PHP version, and services (web server, database, cache), everything pre-answered, then points your app's `.env` at those services, starts the stack, and prints its URLs and credentials. After that, `./laradock start` just starts and reprints them. Re-run the wizard any time with `./laradock setup`. 3 - Enter the workspace, a dev shell with `php`, `composer`, `node`, and `git` inside: ```bash ./laradock workspace ``` 4 - Open [http://localhost](http://localhost). Done. :::tip[Where do I run `artisan`, `composer`, `npm`?] Inside the workspace container, not on your machine. Enter it once with `./laradock workspace` and run commands from there, or prefix a single one: `./laradock exec workspace php artisan migrate`. ::: The CLI hides nothing: it prints every real `docker compose` command it runs, keeps no state, and only ever writes your `.env`. Unknown commands pass straight through (`./laradock logs -f nginx` runs `docker compose logs -f nginx`). Full reference: [The Laradock CLI](https://laradock.io/docs/cli). ## How it works ### The stack Here is the whole picture from where you sit. You work two ways: open your app in a **browser** (Nginx serves it through PHP-FPM), or drop into the **Workspace** terminal to run `artisan`, `composer`, `npm`. Both act on the **same codebase**, mounted straight from your machine. Your code talks to whatever **services** you switch on, add as many as you need, and the same setup ships to production. Click any node to open its source. ```mermaid flowchart LR you(["You
(your machine)"]) subgraph docker["Laradock · your containers on Docker"] direction TB nginx["Nginx
web server"] php["PHP-FPM
runs your PHP"] workspace["Workspace
terminal: php, composer, node, git"] code[/"Your codebase
mounted from your machine"/] subgraph services["Switch on the services you need"] direction LR db[("Database
(MySQL)")] cache[("Cache
(Redis)")] queue["Queue
(RabbitMQ)"] search[("Search
(Meilisearch)")] ai["Local AI
(Ollama)"] more["…100+ more"] end end ship["Ship to production
any server / cloud"] you -->|"in your browser"| nginx you -->|"in your terminal"| workspace nginx -->|"FastCGI"| php php -->|"executes"| code workspace -->|"develops"| code code -.-> db code -.-> cache code -.-> queue code -.-> search code -.-> ai code -.-> more docker -->|"./laradock ship"| ship click nginx "https://github.com/laradock/laradock/blob/master/nginx/compose.yml" click php "https://github.com/laradock/laradock/tree/master/php-fpm/Dockerfile" click workspace "https://github.com/laradock/laradock/blob/master/workspace/compose.yml" click more "/docs/Intro#supported-services" click ship "/docs/production" classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554 classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337 class you toneBlue class nginx,php,workspace toneAmber class code toneRose class db,cache,queue,search,ai,more toneMint class ship toneBlue ``` Solid arrows are how you drive it; dashed arrows are the optional services your code uses. Each service is its own container, switch them on and off per project and they never conflict, and add as many as you like from the [100+ available](https://laradock.io/docs/Intro#supported-services). ### How Laradock configuration works - Your `.env` (created on first run, or `cp .env.example .env` by hand) holds the **shared settings**: paths, PHP version, project name. - Each service keeps its **own settings** pre-filled in its folder: `mysql/defaults.env`, `nginx/defaults.env`, and so on. You never need to copy or edit those files, they work out of the box. - To change **any** setting, shared or per-service, add that line to your `.env` with your value. **Your `.env` always wins over every `defaults.env`.** For example, to run MySQL on another port, add `MYSQL_PORT=3307` to your `.env`. - To discover what a service lets you configure, open its folder's `defaults.env`, it's a short, readable list. - **Upgrading from an older Laradock?** Your existing full `.env` keeps working exactly as before, no changes needed. :::warning One exception: database passwords are set on first run only `MYSQL_PASSWORD`, `POSTGRES_PASSWORD`, and the other database credentials are applied the **first time** that database starts, when it creates its data files on disk. Changing them in `.env` later (even with `./laradock rebuild`) does **not** update an existing database; the old password keeps working. To change a database password for real, either run the change inside the database itself (for example `ALTER USER`), or delete that service's data folder under `DATA_PATH_HOST` so it initializes fresh (this erases that database's data). ::: ### How a request flows Here is what actually happens when a browser hits your app: Nginx hands the request to PHP-FPM, which runs your code and talks to whichever services you enabled, then hands the response back. Anything you queue is passed to the worker and finishes in the background. ```mermaid sequenceDiagram autonumber actor Browser participant Nginx participant PHP as PHP-FPM participant DB as Database (MySQL) participant Cache as Cache (Redis) participant Worker as PHP worker Browser->>Nginx: HTTP request Nginx->>PHP: FastCGI (runs your code) PHP->>DB: query data DB-->>PHP: rows PHP->>Cache: read / write cache Cache-->>PHP: value PHP->>Cache: push queued job PHP-->>Nginx: response Nginx-->>Browser: HTML Cache-->>Worker: deliver job Worker->>DB: process in background ``` The database and cache here are whatever you enabled (Postgres, Valkey, and so on): the shape stays the same. ### How the repository is organized One folder per service, and everything about a service lives in its folder: ``` laradock/ β”œβ”€β”€ docker-compose.yml # the service catalog: shared networks/volumes + include list β”œβ”€β”€ .env.example # shared settings template (copy to .env) β”œβ”€β”€ mysql/ β”‚ β”œβ”€β”€ compose.yml # mysql's container definition β”‚ β”œβ”€β”€ defaults.env # mysql's settings, pre-filled β”‚ └── Dockerfile # mysql's image β”œβ”€β”€ nginx/ β”‚ β”œβ”€β”€ compose.yml β”‚ β”œβ”€β”€ defaults.env β”‚ β”œβ”€β”€ Dockerfile β”‚ └── sites/ # your site configs └── ... # ~100 more services, same pattern ``` So when you want to: | You want to... | Edit... | |---|---| | Change any setting (port, version, password, flag) | your `.env` (add one line, it wins) | | See what a service lets you configure | `/defaults.env` (read-only for you) | | Change a container's structure (mounts, links, ...) | `/compose.yml` | | Change how an image is built | `/Dockerfile`, then rebuild | The root `docker-compose.yml` pulls every service in via Compose `include`, which requires Docker Compose v2.20 or newer. Every top-level folder in the repo is a runnable container, so the folder list is always the up-to-date list of [available services](https://laradock.io/docs/Intro#supported-services). ### How networking works Containers sit on two Docker networks. The **web server** faces the outside on the `frontend` network; **everything else** (PHP-FPM, your database, cache, queue, search, and the background worker) lives on the `backend` network, out of reach from outside. The web server bridges the two so it can pass requests through to PHP-FPM. ```mermaid flowchart LR browser["Client browser"] subgraph frontend["frontend network"] web["Web server
(Nginx / Apache)"] end subgraph backend["backend network"] php["PHP-FPM
(your code)"] db[("Database
(MySQL)")] cache[("Cache
(Redis)")] broker["Message broker
(RabbitMQ)"] search[("Search
(Meilisearch)")] worker["Worker
(background jobs)"] end browser -->|"published ports"| web web -->|"FastCGI"| php php --> db php --> cache php --> broker php --> search broker -.->|"jobs"| worker worker -.-> db click web "https://github.com/laradock/laradock/blob/master/nginx/compose.yml" click php "https://github.com/laradock/laradock/blob/master/php-fpm/compose.yml" click db "https://github.com/laradock/laradock/blob/master/mysql/compose.yml" click cache "https://github.com/laradock/laradock/blob/master/redis/compose.yml" click broker "https://github.com/laradock/laradock/blob/master/rabbitmq/compose.yml" click search "https://github.com/laradock/laradock/blob/master/meilisearch/compose.yml" click worker "https://github.com/laradock/laradock/blob/master/php-worker/compose.yml" classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d class web,php,worker toneAmber class db,cache,broker,search toneMint ``` The browser reaches the web server through **published ports**, not a Docker network. Switch the driver for both networks with `NETWORKS_DRIVER` in your `.env`. More: [Networking](https://laradock.io/docs/networking). ## Running multiple projects One Laradock can serve one project, or many. Run an **isolated** Laradock per project (separate containers and data), or serve **several sites from one** Laradock with a web-server config each. Different PHP versions per project are supported too. β†’ Full guide: [Running Multiple Projects](https://laradock.io/docs/multiple-projects) Β· [Multiple PHP Versions](https://laradock.io/docs/multiple-php-versions) ## Manual setup (advanced, full control) {#manual-setup} Rather wire things up by hand? Everything the CLI does, you can do with plain `docker compose`, same files, same result. It's the path for advanced users who want full control over exactly which containers run and how they're configured. β†’ Full guide: [Manual Setup (without the CLI)](https://laradock.io/docs/manual-setup) ================================================================ # Laradock vs Others Source: https://laradock.io/docs/laradock-alternatives ================================================================ import DocCardList from '@theme/DocCardList'; *Laradock vs DDEV, Laravel Sail, Laravel Herd, Laravel Valet, Lando, Laragon, Local WP, XAMPP / MAMP, Homestead / Vagrant, Dev Containers, manual installs, and writing your own Docker Compose.* Setting up a local PHP environment in 2026, you have four paths. This page lays out every Laradock alternative honestly, compares the popular tools on each path, and tells you when Laradock is the right choice and when it is not. ## Your four options **1. Install everything natively on your machine.** Either fully by hand (`brew install php mysql nginx`, `apt install ...`), via a classic bundle ([XAMPP](https://www.apachefriends.org/), [MAMP](https://www.mamp.info/), [Laragon](https://laragon.org/) on Windows), a modern native app ([Laravel Valet](https://laravel.com/docs/valet) or [Laravel Herd](https://herd.laravel.com/) on macOS/Windows), or a WordPress-only GUI app ([Local WP](https://localwp.com/)). Fastest raw performance and often the friendliest onboarding, but your machine accumulates global installs, version conflicts between projects, and a setup that never quite matches production or your teammates' laptops. Smaller tools in the same family worth knowing about: [WordPress Studio](https://developer.wordpress.com/studio/) (WordPress.com's native local tool), [DevKinsta](https://kinsta.com/devkinsta/) (Kinsta-hosting-specific), and the older [VVV](https://varyingvagrantvagrants.org/) / Chassis Vagrant boxes for WordPress, both now largely superseded by Local WP and DDEV. **2. Run a virtual machine.** [Vagrant](https://developer.hashicorp.com/vagrant) with Laravel's old official [Homestead](https://github.com/laravel/homestead) box. This was the standard before containers: a full Linux VM per environment. Heavy on RAM and disk, slow to boot, and Homestead is no longer actively promoted; containers made this path mostly historical. **3. Use Docker through a management tool.** A CLI you install that generates and drives Docker for you: [DDEV](https://ddev.com/), [Lando](https://lando.dev/), Laravel's official [Sail](https://laravel.com/docs/sail), or editor-driven [Dev Containers](https://containers.dev/) (VS Code / GitHub Codespaces). Great convenience, but the actual Docker machinery is generated or abstracted away; you learn the tool's commands, and you depend on the tool. **4. Use Docker directly.** Either write and maintain your own `docker-compose.yml` (days of wiring, then ongoing upkeep), or use **Laradock**: the wiring is already done for 100+ services, and nothing else is added. No binary to install, no CLI to learn, no hidden generated files. You run plain `docker compose` commands against readable files you fully own; an optional zero-install wizard (`./laradock setup`, the [Laradock CLI](https://laradock.io/docs/cli)) handles the first-run choices without hiding anything. That is Laradock's position in one sentence: **it IS option 4, raw Docker, with the boring wiring done for you.** The lightest possible layer: zero installation, zero new commands, zero magic, and every file open for you to read, edit, or break. ## Why pick Laradock in 2026 If you last used Laradock as "just Laravel plus Docker," it has grown well past that. Four things now set it apart, and **no competing tool combines all four**: - πŸ€– **An AI agent can run it for you.** Laradock ships [`AGENTS.md`](https://github.com/laradock/laradock/blob/master/AGENTS.md) plus rule files for Claude Code, Cursor, Gemini CLI, Cline, and Windsurf, a machine-readable [`llms.txt`](https://laradock.io/llms.txt), and raw-Markdown docs (append `.md` to any page). Open the repo in your coding agent and say *"Set up Laradock for this project"*: it reads the layout and drives the whole stack for you. No other PHP dev environment ships this. - 🧠 **A one-click local AI stack.** `./laradock start ollama` runs a local LLM; vector databases ([Qdrant](https://laradock.io/docs/services/qdrant), [Weaviate](https://laradock.io/docs/services/weaviate), [Chroma](https://laradock.io/docs/services/chroma), [pgvector](https://laradock.io/docs/services/pgvector)), a model gateway ([LiteLLM](https://laradock.io/docs/services/litellm)), agent automation ([n8n](https://laradock.io/docs/services/n8n), [Flowise](https://laradock.io/docs/services/flowise)), and an [MCP server](https://laradock.io/docs/services/mcp) that lets your coding agent read your real database schema are one command each. Build AI features on your own machine with no cloud bills. No competitor bundles these. - πŸ—£οΈ **A plain-English CLI, no Docker knowledge needed.** `./laradock start`, `stop`, `logs`, `db`, `test`, `share`. As easy as the appliance tools (DDEV, Lando), but it hides nothing: it prints the real `docker compose` command before running it, installs no binary, and writes only your `.env`. - πŸš€ **It follows you to production.** [`./laradock ship`](https://laradock.io/docs/production) builds one hardened image that runs on a server, Kamal, Kubernetes, or any managed cloud. The dev-only tools (Sail, Herd, Valet, XAMPP) stop at your laptop. Each competitor still wins on its one thing: Herd on raw native speed, DDEV on automatic HTTPS routing, Laragon on Windows polish, Local WP on pure WordPress. Laradock's edge is the **combination**: transparent *and* easy, dev *and* production, human *and* AI-operable. The honest per-tool breakdown is below. ## Laradock alternatives at a glance Laradock lives in the "use Docker directly" camp, so the fairest comparison splits into two groups: the other **Docker-based tools** you'd weigh it against, and the **native tools** that install PHP straight onto your machine. ### Docker-based tools Laradock vs the other ways to run PHP in Docker: your own hand-written Compose, Laravel's Sail, and the generate-it-for-you CLIs (DDEV, Lando). | | **Laradock** | **Your own Compose** | **Laravel Sail** | **DDEV** | **Lando** | |---|---|---|---|---|---| | What it is | Pre-wired Docker Compose files | DIY Docker files | Laravel's Docker scaffold | CLI that generates Docker | CLI that generates Docker | | You install | Nothing (git clone) | Nothing | Nothing (ships with Laravel) | The `ddev` binary | The `lando` binary | | Commands you use | `./laradock` (plain English) or `docker compose` | Plain `docker compose` | `sail` wrapper | `ddev` CLI | `lando` CLI | | Guided setup wizard | βœ… optional (`./laradock setup`) | ❌ | βœ… | βœ… | βœ… | | Docker files visible & editable | βœ… All of them | βœ… You wrote them | βœ… Published into your app | ❌ Generated & hidden | ❌ Generated & hidden | | Ready-made services | 100+ | 0 (you write each) | ~10 | ~50 add-ons | ~15 recipes | | Works with any PHP project | βœ… | βœ… | Laravel only | βœ… (CMS focus) | βœ… (CMS focus) | | Per-project PHP version | βœ… | βœ… | βœ… | βœ… | βœ… | | Auto HTTPS + `.test` domains | Manual (or Traefik/Caddy service) | Manual | Manual | βœ… Automatic | βœ… Automatic | | Skills you build | Real Docker (transferable) | Real Docker (transferable) | Sail-specific | DDEV-specific | Lando-specific | | Production parity | High (same containers) | High | High | Medium | Medium | | **Ships to production** | βœ… `./laradock ship` | ⚠️ DIY | ❌ dev-only | ⚠️ limited | ⚠️ limited | | **One-click AI services** (LLM + vector DB) | βœ… Ollama, Qdrant, pgvector… | ❌ DIY | ❌ | ❌ | ❌ | | **AI agent-operable** (`AGENTS.md` + `llms.txt`) | βœ… | ❌ | ❌ | ❌ | ❌ | | Price | Free, | Free | Free | Free | Free | ### Native (no-Docker) tools Laradock vs the tools that install PHP, a web server, and a database straight onto your OS. They're fast and simple to start, but nothing is isolated and nothing resembles your production server. | | **Laradock** | **Herd** | **Laragon** | **Valet** | **XAMPP / MAMP** | |---|---|---|---|---|---| | What it is | Pre-wired Docker Compose files | Native PHP/Nginx app | Native bundle (Windows) | Native Nginx + DnsMasq | Native Apache/PHP bundle | | You install | Nothing (git clone) | Desktop app | Desktop app | CLI (Composer + Homebrew) | Desktop app | | Commands you use | `./laradock` (plain English) or `docker compose` | GUI + `herd` | GUI | `valet` CLI | GUI | | Guided setup wizard | βœ… optional (`./laradock setup`) | βœ… (GUI) | βœ… (GUI) | ❌ | βœ… (GUI) | | Runs in isolated containers | βœ… | ❌ native | ❌ native | ❌ native | ❌ native | | Keeps your machine clean | βœ… nothing on host | ❌ installs on host | ❌ installs on host | ❌ installs on host | ❌ installs on host | | Ready-made services | 100+ | A handful (Pro) | One-click installers | None (add via Homebrew) | Apache + MySQL | | Works with any PHP project | βœ… | Laravel focus | βœ… | βœ… | βœ… | | Platforms | Linux, macOS, Windows | macOS, Windows only | Windows only | macOS only | Linux, macOS, Windows | | Per-project PHP version | βœ… | βœ… | βœ… | βœ… | ❌ (global switch) | | Auto HTTPS + `.test` domains | Manual (or Traefik/Caddy service) | βœ… Automatic | βœ… Automatic | βœ… Automatic | ❌ | | Production parity | High (same containers) | None (native) | None (native) | None (native) | None (native) | | **Ships to production** | βœ… `./laradock ship` | ❌ dev-only | ❌ dev-only | ❌ dev-only | ❌ dev-only | | **One-click AI services** (LLM + vector DB) | βœ… Ollama, Qdrant, pgvector… | ❌ | ❌ | ❌ | ❌ | | **AI agent-operable** (`AGENTS.md` + `llms.txt`) | βœ… | ❌ | ❌ | ❌ | ❌ | | Price | Free | Free / Pro paid | Free | Free | Free | ## Head-to-head ### Laradock vs DDEV DDEV is an appliance: press `ddev start` and a polished environment appears, with automatic HTTPS, `myproject.ddev.site` domains, and per-project isolation handled for you. The trade: the Docker files are generated and regenerated behind your back, you debug the generator instead of a Dockerfile, and everything you learn is DDEV-specific. Laradock is the opposite: nothing is hidden, every Dockerfile and compose file is yours, and its 100+ services include things DDEV has no add-on for (Kafka, ClickHouse, local LLMs like Ollama, HAProxy, GitLab). **Pick DDEV** if you run an agency juggling many similar CMS sites (Drupal, TYPO3, WordPress) and never want to see Docker. **Pick Laradock** if you want full control, an unusual stack, or Docker knowledge that transfers to production. *Full breakdown with the same app set up in both tools: [Laradock vs DDEV](https://laradock.io/docs/laradock-vs-ddev).* ### Laradock vs Laravel Sail Sail is official, minimal, and Laravel-only: a small compose file with ~10 services and a `sail` command wrapper. It is a great default for a standard Laravel app. You outgrow it the day you need a service it does not ship (search cluster, message broker, a second database, a vector DB) or a non-Laravel project. Laradock is framework-agnostic, offers 100+ services behind the identical `docker compose up -d {service}` workflow, and needs no wrapper script. It also goes where Sail deliberately stops: Sail is dev-only, while `./laradock ship` takes the same stack to production, a single server, Kubernetes (EKS/GKE/AKS), or a managed cloud. **Pick Sail** for a simple, purely Laravel app with vanilla needs. **Pick Laradock** when your stack is bigger than Sail's list, you juggle multiple frameworks, you need the same environment to reach production, or you would rather use Docker directly than through a wrapper. *Full breakdown with real commands for both: [Laradock vs Laravel Sail](https://laradock.io/docs/laradock-vs-laravel-sail).* ### Laradock vs Laravel Herd Herd is not Docker at all: it installs PHP and Nginx natively on macOS or Windows, which makes it the fastest option for raw requests and the nicest one-click experience for solo Laravel work. The costs: no Linux support, services beyond PHP need Herd Pro (paid) or separate installs, your environment does not resemble production, and your machine is no longer clean. **Pick Herd** if you are a solo Laravel developer on a Mac who values speed above parity. **Pick Laradock** if you want production-like containers, Linux support, a full service catalog, or a host machine with nothing installed on it. *Full breakdown: [Laradock vs Laravel Herd](https://laradock.io/docs/laradock-vs-laravel-herd).* ### Laradock vs Lando Lando is DDEV's closest cousin: a `.lando.yml` recipe file and a CLI that generates Docker behind the scenes, popular in Drupal and WordPress agencies. Same appliance trade-offs as DDEV with a smaller team behind it. Everything in the DDEV section applies. **Pick Lando** if your team already standardized on it. **Pick Laradock** for transparency, breadth of services, and no tool between you and Docker. *Full breakdown with a migration guide: [Laradock vs Lando](https://laradock.io/docs/laradock-vs-lando).* ### Laradock vs XAMPP / MAMP The classic bundles install Apache, MySQL, and PHP globally on your machine. They still work, but they are the reason "works on my machine" became a meme: one global PHP version, config drift between teammates, no isolation between projects, and nothing resembling your server. Laradock gives you the same one-download convenience with none of those problems, because everything runs in disposable containers. **Pick XAMPP/MAMP** only if Docker is not an option on your machine. **Pick Laradock** otherwise; the switch is one `git clone` and one command. *Full breakdown with a 10-minute migration guide: [Laradock vs XAMPP / MAMP](https://laradock.io/docs/laradock-vs-xampp).* ### Laradock vs Laragon Laragon is the best-in-class version of the same native-install idea, Windows-only, fast, and genuinely polished, with one-click app installers and automatic virtual hosts. Its ceiling is the same as every native bundle's: one Windows machine, one global set of services, nothing resembling a Linux server. **Pick Laragon** if you are on Windows and want the fastest, most polished native setup available. **Pick Laradock** for cross-platform consistency and a service list Laragon doesn't ship. *Full breakdown with a migration guide: [Laradock vs Laragon](https://laradock.io/docs/laradock-vs-laragon).* ### Laradock vs Laravel Valet Valet is the leanest native option of all: no GUI, ~7MB of RAM, just Nginx and DnsMasq quietly serving `.test` domains on macOS. It ships with nothing else, though, no database, no Redis, you add every service yourself via Homebrew, and it never leaves macOS. **Pick Valet** if you're on macOS and want the smallest possible native footprint. **Pick Laradock** for Linux/Windows support or services beyond what Homebrew conveniently offers. *Full breakdown with a migration guide: [Laradock vs Laravel Valet](https://laradock.io/docs/laradock-vs-valet).* ### Laradock vs Local WP Local WP is the WordPress specialist: a polished desktop GUI that creates a fully working WordPress install in about two minutes, with one-click deploys to WP Engine or Flywheel. It only does WordPress, though; the moment your work spans other frameworks or CMSs, its scope becomes a ceiling. **Pick Local WP** if you build WordPress exclusively and want the smoothest GUI experience, especially on WP Engine/Flywheel hosting. **Pick Laradock** if you work across frameworks or prefer file-based config over a GUI. *Full breakdown with a migration guide: [Laradock vs Local WP](https://laradock.io/docs/laradock-vs-local-wp).* ### Laradock vs installing everything manually (no tool at all) The purist native path: `brew install php@8.4 mysql redis nginx` (or `apt` on Linux), wire the configs yourself. It works, and plenty of seniors run this way. The costs are permanent: one global PHP unless you juggle version managers, config files scattered across your OS, upgrades that break other projects, teammates each with a slightly different setup, and nothing disposable; uninstalling never quite cleans up. Laradock gives you the same "no magic" feeling with isolation: every project gets its own versions, and deleting the containers removes every trace. **Stay manual** if you run one project on one machine and know your OS inside out. **Pick Laradock** the moment a second project, a second machine, or a second teammate appears. *Full breakdown: [Laradock vs Installing PHP Manually](https://laradock.io/docs/laradock-vs-manual-install).* ### Laradock vs Homestead / Vagrant Homestead was Laravel's official pre-Docker answer: a full Ubuntu VM managed by Vagrant. It still works, but you pay VM prices: gigabytes of RAM held hostage, slow boots, full-OS maintenance, and shared-folder performance pain. Containers deliver the same isolation at a fraction of the weight, which is why the ecosystem moved on. If you are on Homestead today, Laradock is the natural next step: the same "everything included" philosophy, minus the VM. **Stay on Homestead** only if your team is locked into Vagrant workflows. **Pick Laradock** for the same batteries-included experience with faster startup and a fraction of the resources. *Full breakdown with a migration guide: [Laradock vs Homestead / Vagrant](https://laradock.io/docs/laradock-vs-homestead).* ### Laradock vs Dev Containers (VS Code) / Codespaces [Dev Containers](https://containers.dev/) put your editor inside a container defined by `devcontainer.json`; GitHub Codespaces runs that in the cloud. It shines for onboarding ("open repo, click, code") and standardizing editor tooling. But it is editor-centric: the container follows VS Code, multi-service stacks still need a compose file underneath (which you write yourself), and outside VS Code / JetBrains the experience degrades. Laradock is editor-agnostic infrastructure: your stack runs the same whether you code in Vim, PhpStorm, VS Code, or over SSH, and the compose wiring Dev Containers would ask you to write is already done. **Pick Dev Containers/Codespaces** if your team lives in VS Code and wants one-click cloud onboarding. **Pick Laradock** if the environment should belong to the project, not to the editor. They also combine well: a thin `devcontainer.json` can point at Laradock's services. *Full breakdown including the combo setup: [Laradock vs Dev Containers](https://laradock.io/docs/laradock-vs-devcontainers).* ### Laradock vs writing your own Docker Compose Writing your own compose file is the purist path and exactly what Laradock is, minus the days of work: choosing base images, wiring networks, tuning PHP images with the right extensions, solving permissions, and maintaining all of it as versions move. Laradock is that work already done and battle-tested since 2015, in plain files you can diff against what you would have written. **Write your own** if your stack is tiny and you enjoy the craft. **Pick Laradock** to skip a week of wiring and keep 100% of the control, since the files are yours anyway. *Full breakdown: [Laradock vs Plain Docker Compose](https://laradock.io/docs/laradock-vs-docker-compose).* ## So which one should you choose? - **Agency with many similar CMS sites, allergic to Docker details** β†’ DDEV (or Lando). - **Solo Laravel developer on macOS/Windows who wants maximum speed** β†’ Herd. - **Simple Laravel app, vanilla needs, official tooling** β†’ Sail. - **You want control, breadth, production parity, transferable skills, and zero extra tooling** β†’ **Laradock**. - **You want an environment an AI agent can fully operate, or a one-click local AI / vector stack** β†’ **Laradock** (no other tool ships this today). - **You need the same environment to reach production, not just your laptop** β†’ **Laradock** (`./laradock ship`). - **Docker unavailable** β†’ XAMPP/MAMP/Laragon, or a manual native install. - **WordPress only, want the smoothest GUI, especially on WP Engine/Flywheel** β†’ Local WP. - **macOS minimalist who wants the leanest native footprint** β†’ Valet. - **Windows user who wants the fastest native one-click setup** β†’ Laragon. - **Team lives in VS Code / wants cloud onboarding** β†’ Dev Containers or Codespaces (optionally on top of Laradock). - **Still on Homestead/Vagrant** β†’ Laradock is the modern equivalent, same philosophy without the VM. If you picked Laradock, the [Getting Started guide](https://laradock.io/docs/getting-started) takes about five minutes. ## Head-to-head comparisons Read the detailed comparison for the tool you're weighing Laradock against: ================================================================ # Laradock vs DDEV Source: https://laradock.io/docs/laradock-vs-ddev ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is DDEV? [DDEV](https://ddev.com/) is a free, open-source command-line tool for running local PHP development environments in Docker. You install one binary, run `ddev config` and `ddev start`, and it generates and manages all the Docker containers for you behind the scenes, database, web server, PHP, the works, without you writing or seeing a Dockerfile. It is popular in the Drupal, WordPress, and TYPO3 communities, and works with Laravel too. This page compares it to Laradock, which takes the opposite approach: instead of a tool that generates Docker for you, Laradock gives you the Docker files themselves, already written. *Same goal, two philosophies: DDEV generates and hides the Docker machinery behind a CLI; Laradock hands you the Docker machinery pre-wired and gets out of the way. This page sets up the same Laravel project with both, honestly.* **TL;DR:** pick [DDEV](https://ddev.com/) if you run many similar CMS projects and never want to see a Dockerfile. Pick Laradock if you want to see (and own) everything, need services DDEV has no add-on for, or want your Docker knowledge to transfer beyond the tool. ## Setting up a Laravel app with DDEV DDEV is a Go binary you install first (Homebrew, installer script, or package manager). Then: ```bash mkdir my-app && cd my-app ddev config --project-type=laravel --docroot=public ddev start -y ddev composer create-project laravel/laravel ddev launch ``` Your site is live at `https://my-app.ddev.site` with trusted HTTPS. Need Redis? ```bash ddev add-on get ddev/ddev-redis ddev restart ``` Change PHP version: ```bash ddev config --php-version=8.4 && ddev restart ``` Day to day you talk to the tool: `ddev ssh`, `ddev artisan`, `ddev composer`, `ddev import-db`. The actual compose files are generated into `.ddev/` and regenerated on every start; they are not yours to edit directly. ## The same thing with Laradock Laradock is a git clone; there is nothing to install: ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Then, inside the workspace: `composer create-project laravel/laravel .` Your site is live at `http://localhost`. Redis was one word in the `start` command; the same is true for 100+ other services (`./laradock start ollama`, `rabbitmq`, `elasticsearch`, ...). Change PHP version: set `PHP_VERSION=8.4` in `.env`, then `./laradock rebuild php-fpm workspace` (or `docker compose build php-fpm workspace`). Prefer a guided start? `./laradock setup` (the optional, zero-install [CLI](https://laradock.io/docs/cli)) asks the same three-questions-style wizard, then prints every real command it runs. Day to day you talk to Docker itself: `./laradock enter workspace`, `./laradock logs mysql`, plain `artisan` and `composer` inside the workspace. Every file involved (`nginx/compose.yml`, `php-fpm/Dockerfile`, ...) is readable and permanently editable. ## Side by side | | **DDEV** | **Laradock** | |---|---|---| | Install | ddev binary | nothing (git clone) | | First run | `ddev config` + `ddev start` | `./laradock setup` + `./laradock start` (or plain `docker compose`) | | URLs | `https://my-app.ddev.site` automatic | `http://localhost` (or wire Traefik/Caddy yourself) | | HTTPS | Automatic, trusted | Manual (Caddy/Traefik/certbot services included) | | Services | ~50 curated add-ons | 100+ shipped folders (incl. Kafka, ClickHouse, Ollama, GitLab) | | Docker files | Generated, hidden, regenerated | Plain files you own and edit | | Commands | `ddev *` vocabulary | standard `docker compose *` | | Multi-project isolation | Automatic per project | Manual (`COMPOSE_PROJECT_NAME` + `DATA_PATH_HOST` per project) | | Frameworks | CMS-focused presets (Drupal, TYPO3, WordPress, Laravel) | Any PHP project, framework-agnostic | | Production deployment | Local dev tool (generated files don't leave your machine) | `./laradock ship` β†’ hardened image for a server, Kubernetes (EKS/GKE/AKS), or managed cloud | | Skills you build | DDEV-specific | Transferable Docker | ## Choose DDEV if... - You juggle many similar CMS sites (Drupal, TYPO3, WordPress agency work) and want identical, isolated environments with zero Docker exposure. - Automatic HTTPS and per-project domains matter more to you than seeing how they work. - You are happy inside a curated add-on ecosystem. ## Choose Laradock if... - You want full control: every Dockerfile, every config, yours to read and change. - Your stack goes beyond the add-on registry (message brokers, search clusters, local LLMs, monitoring). - You want to learn real Docker while you work, and keep those skills in production. - You do not want to install or trust another binary between you and your containers. - **You want dev and production to be the same containers.** DDEV is a local tool; Laradock's `./laradock ship` deploys the exact stack you built to a server, Kubernetes, or a managed cloud. See [Deploy to Production](https://laradock.io/docs/production). ## Already on DDEV? Migrating takes minutes 1. **Export your database** while DDEV still runs: `ddev export-db --file=backup.sql.gz && gunzip backup.sql.gz` 2. **Stop DDEV:** `ddev stop` (keep the `.ddev/` folder until you are confident; nothing conflicts). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start nginx mysql redis workspace` (or `docker compose up -d nginx mysql redis workspace`) 5. **Import the database:** `./laradock exec -T mysql mysql -uroot -proot default < ../backup.sql` (or use phpMyAdmin: `./laradock start phpmyadmin`, then `localhost:8081`). 6. **Update your app's `.env`:** DDEV's `DB_HOST=db` becomes `DB_HOST=mysql`, credentials are in `mysql/defaults.env` (user `default`, password `secret` by default). 7. Your site now answers at `http://localhost` instead of `https://my-app.ddev.site`. ## Frequently Asked Questions ### Is DDEV free? Yes, DDEV is free and open-source (BSD-3 license). There is no paid tier; hosting, if you use DDEV's optional add-ons for it, is billed separately by whichever provider you choose. ### Does DDEV require Docker? Yes. DDEV is a CLI that generates and drives Docker Compose configurations behind the scenes; you still need Docker Desktop (or Colima/OrbStack) installed and running. ### Can I use DDEV with Laravel? Yes, `laravel` is one of DDEV's built-in project types (`ddev config --project-type=laravel`), alongside CMS-focused types like WordPress, Drupal, and TYPO3. ### Can I edit DDEV's generated Docker files? Not directly and expect it to stick: files under `.ddev/` are regenerated by DDEV and files it manages in your app (like `wp-config-ddev.php`) carry a `#ddev-generated` marker; DDEV rewrites anything still carrying that marker on every start. Delete the marker line to make a file permanently yours. ### Is DDEV better than Laradock? Neither is strictly better; they optimize for different things. DDEV optimizes for zero-Docker-exposure convenience with automatic HTTPS and curated add-ons. Laradock optimizes for full transparency and the largest ready-made service catalog. See the [full comparison](https://laradock.io/docs/laradock-alternatives) for a breakdown by use case. See the full landscape, including Sail, Herd, Lando and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Laravel Sail Source: https://laradock.io/docs/laradock-vs-laravel-sail ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Sail? [Laravel Sail](https://laravel.com/docs/sail) is Laravel's own, official command-line interface for running a Laravel application in Docker. It ships automatically with every new Laravel project: no separate install, just a `sail` command and a small `docker-compose.yml` file that Laravel generates for you, covering PHP, a database, and a handful of common services. It is intentionally minimal and Laravel-specific. This page compares it to Laradock, a framework-agnostic alternative with 100+ pre-configured services instead of Sail's shorter list, used directly through plain `docker compose` rather than a wrapper command. *Sail is Laravel's official Docker scaffold: small, clean, Laravel-only. Laradock is the framework-agnostic catalog: 100+ services behind the same plain Docker workflow. This page runs the same app on both.* **TL;DR:** pick [Sail](https://laravel.com/docs/sail) for a vanilla Laravel app with vanilla needs; it is official and it is enough. Pick Laradock the day your stack outgrows Sail's service list, you run more than Laravel, or you would rather use `docker compose` directly than through a wrapper script. ## Setting up with Sail For a brand-new app, one command scaffolds everything: ```bash curl -s "https://laravel.build/my-app?with=mysql,redis" | bash cd my-app && ./vendor/bin/sail up -d ``` For an existing app: `composer require laravel/sail --dev`, then `php artisan sail:install` and pick your services from the menu (MySQL, Postgres, Redis, Meilisearch, Mailpit, Selenium, and a few more). Day to day, everything goes through the wrapper: `sail up`, `sail artisan migrate`, `sail composer require`, `sail test`. Change PHP version: edit `compose.yaml`, point the build context at another runtime (`./vendor/laravel/sail/runtimes/8.3`), change the `image` name to match, then `sail build --no-cache`. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Inside the workspace: artisan, composer, npm all live here. Or let the optional [CLI](https://laradock.io/docs/cli) do the choosing: `./laradock setup` detects Laravel and pre-selects nginx/mysql/redis, exactly like `sail:install`'s menu, then shows every real command it runs. Day to day you use Docker directly: `./laradock exec workspace php artisan migrate`, `./laradock logs nginx -f`, `./laradock stop`. Change PHP version: `PHP_VERSION=8.3` in `.env`, then `./laradock rebuild php-fpm workspace` (or `docker compose build php-fpm workspace`). Runs anything from PHP 5.6 to 8.5, which Sail does not attempt (great for legacy projects). ## Side by side | | **Laravel Sail** | **Laradock** | |---|---|---| | Ships with | Laravel itself (official) | git clone | | Services | ~10 (chosen at install) | 100+ (start any, any time) | | Frameworks | Laravel only | Any PHP project | | Commands | `sail *` wrapper | standard `docker compose *` | | Web server | Built-in PHP server (`artisan serve`) by default | Real NGINX / Apache / Caddy, production-style | | PHP versions | 8.0 - 8.4 runtimes | 5.6 - 8.5 | | Adding a service later | Only if Sail supports it (else hand-edit compose.yaml) | `docker compose up -d {service}` | | Dev shell | none (commands via `sail`) | `workspace` container with Composer, Node, git, and dozens of tools | | Config | one compose.yaml in your repo | per-service folders + one `.env` | | Production deployment | **Dev only** β€” Sail is explicitly not meant for production | `./laradock ship` β†’ hardened image for a server, **Kubernetes** (EKS/GKE/AKS), or managed cloud (ECS, Cloud Run, Fly) | ## Command-to-command map Everything you do with `sail` has a Laradock equivalent. Sail routes every action through one `sail` wrapper; Laradock uses plain-English verbs for the stack and runs your dev tools inside the `workspace` container (or via a one-off `exec`). Same capabilities, no wrapper lock-in. | Task | Laravel Sail | Laradock | |---|---|---| | Start the stack | `sail up -d` | `./laradock start` | | Stop the stack | `sail stop` | `./laradock stop` | | Restart | `sail restart` | `./laradock restart` | | Rebuild images | `sail build --no-cache` | `./laradock rebuild` | | Open a shell in the app container | `sail shell` / `sail root-shell` | `./laradock workspace` / `./laradock workspace --root` | | Run Artisan | `sail artisan migrate` | `./laradock exec workspace php artisan migrate` | | Run Composer | `sail composer require ...` | `./laradock exec workspace composer require ...` | | Run a raw PHP command | `sail php script.php` | `./laradock exec workspace php script.php` | | Run Node / NPM | `sail npm run dev` | `./laradock exec workspace npm run dev` | | Run the test suite | `sail test` | `./laradock test` (auto: artisan β†’ pest β†’ phpunit) | | Browser tests | `sail dusk` | `./laradock start selenium` + `./laradock test` | | REPL | `sail tinker` | `./laradock exec workspace php artisan tinker` | | Open a database shell | (connect manually with creds) | `./laradock db` (auto-detects MySQL/MariaDB/Postgres) | | Open the app in a browser | (type `http://localhost`) | `./laradock open` (or `open mailpit`, `open phpmyadmin`) | | Public URL for your local site | `sail share` | `./laradock share` (cloudflared / ngrok) | | Preview sent emails | Mailpit UI (bundled) | `./laradock start mailpit` β†’ `./laradock open mailpit` | | See what's running | `sail ps` | `./laradock info` | | Change PHP version | edit `compose.yaml` + `sail build` | `./laradock set PHP_VERSION=8.4` + `./laradock rebuild` | | Add a service | `sail add` (from Sail's menu) | `./laradock start {service}` (100+ available) | | Deploy to production | not supported (dev-only) | `./laradock ship` β†’ server / Kubernetes / cloud | | Drop to raw Docker | `sail` hides it | `./laradock ` passes straight to `docker compose` | Two differences worth noting: Sail bundles every tool call under the `sail` verb, while Laradock keeps your dev tools (`artisan`, `composer`, `npm`) *inside* the `workspace` shell, so a single `./laradock workspace` drops you where they all live, and you type them exactly as you would anywhere else. And where Sail stops at your laptop, the same Laradock stack keeps going all the way to production. ## Choose Sail if... - Your app is pure Laravel and your stack is inside Sail's menu. - You value "official" and minimal above everything else. - Your team already knows the `sail` command by heart. ## Choose Laradock if... - You need anything beyond Sail's list: RabbitMQ, Kafka, Elasticsearch clusters, ClickHouse, vector DBs, local LLMs, monitoring; with Laradock each one is a single `up` command away. - You also work on non-Laravel projects and want one environment for all of them. - You want a production-style web server (NGINX/Apache/Caddy) instead of `artisan serve` in a container. - You maintain legacy apps on PHP 5.6/7.x that Sail cannot run. - You prefer no wrapper: what you learn is plain Docker Compose. - **You want the same stack to reach production.** Sail is explicitly dev-only; Laradock's `./laradock ship` builds a hardened image of your app and deploys it to a single server, Kubernetes (EKS/GKE/AKS), or a managed cloud (AWS ECS, Cloud Run, Fly), the exact containers you developed against. See [Deploy to Production](https://laradock.io/docs/production). ## Already on Sail? The service names even match Sail and Laradock both call the containers `mysql` and `redis`, so your app's `.env` barely changes. 1. **Export your database** while Sail still runs: `./vendor/bin/sail exec mysql mysqldump -uroot -ppassword laravel > backup.sql` (adjust db name/creds to your `.env`). 2. **Stop Sail:** `./vendor/bin/sail down` 3. **Add Laradock** inside your project: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start nginx mysql redis workspace` (or `docker compose up -d nginx mysql redis workspace`) 5. **Import the database:** `./laradock exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's `.env`:** `DB_HOST=mysql` and `REDIS_HOST=redis` stay the same; change `DB_DATABASE`/`DB_USERNAME`/`DB_PASSWORD` to Laradock's (in `mysql/defaults.env`) or set yours in Laradock's `.env`. 7. Optional cleanup once you are settled: `composer remove laravel/sail --dev` and delete Sail's `compose.yaml`. ## Frequently Asked Questions ### Is Laravel Sail free? Yes. Sail ships as a Composer dev-dependency with every new Laravel install and is fully free and open-source (MIT license), maintained by the Laravel team. ### Does Sail only work with Laravel? Yes, Sail is built specifically for Laravel applications; it is not a general-purpose PHP Docker tool. For non-Laravel PHP projects (Symfony, WordPress, plain PHP), you need something framework-agnostic like Laradock. ### What services does Sail support? Sail's installer offers a curated list including MySQL, PostgreSQL, MariaDB, MongoDB, Redis, Valkey, Memcached, Meilisearch, Typesense, MinIO, Mailpit, RabbitMQ, and Selenium, roughly 15 services, selected at install time via `sail:install` or added later with `sail:add`. ### Can I add a service to Sail after installing? Yes, run `php artisan sail:add` and pick additional services from the same menu `sail:install` uses; it updates your `compose.yaml` and re-runs the environment wiring. ### Is Sail slow on macOS or Windows? It can be: Sail's file-sharing performance depends entirely on Docker Desktop's bind-mount speed, a known pain point for `vendor/`-heavy PHP projects. Recent Docker Desktop VirtioFS improvements help significantly; this is a Docker Desktop limitation, not specific to Sail or Laradock. See the full landscape, including DDEV, Herd, Lando and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Laravel Herd Source: https://laradock.io/docs/laradock-vs-laravel-herd ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Herd? [Laravel Herd](https://herd.laravel.com/) is a native macOS and Windows application, built by the Laravel team, that installs PHP, a web server, and local `.test` domains directly onto your computer, no Docker, no containers, no virtual machine. You open the app, and your PHP projects are served instantly. It trades container isolation for raw native speed and a one-click setup. This page compares it to Laradock, which runs everything in Docker containers instead: slightly more setup, but an environment that matches your Linux production server and works on Linux too, which Herd does not support. *Herd and Laradock solve the same problem from opposite ends: Herd installs a native PHP toolchain on your Mac or Windows machine for maximum speed; Laradock keeps your machine untouched and runs everything in production-style containers.* **TL;DR:** pick [Herd](https://herd.laravel.com/) if you are a solo Laravel developer on macOS/Windows and raw speed beats everything. Pick Laradock if you want containers that resemble production, work on Linux, need real services for free, or want nothing installed on your machine. ## Setting up with Herd Download and run the Herd app (macOS or Windows; there is no Linux version). It installs PHP, Nginx and dnsmasq natively, then: ```bash cd ~/Herd laravel new my-app ``` That's it: `http://my-app.test` works immediately; any project inside the parked `~/Herd` folder is served automatically, and `herd link` serves a folder living elsewhere. PHP versions switch per site in seconds (PHP 7.4 to 8.5), pinnable per project. The catch appears at the services layer: MySQL, Redis, queues, and mail capture are part of **Herd Pro** (paid), or you install and manage them yourself. And because everything is native, your local runtime looks nothing like your Linux production server. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Inside the workspace: artisan, composer, node, all ready to go. No app installed, no native PHP, no menu bar icon: your machine stays clean, and `./laradock remove` leaves zero traces. Every service is free and unlimited: databases, queues, search, mail catchers, monitoring, local LLMs; 100+ of them, one command each. Change PHP version: `PHP_VERSION=8.3` in `.env` + rebuild. Different projects can run different versions side by side in their own containers. ## Side by side | | **Laravel Herd** | **Laradock** | |---|---|---| | Runs as | Native app (PHP/Nginx on your OS) | Docker containers | | Platforms | macOS, Windows | Linux, macOS, Windows | | Raw speed | Fastest (no container overhead) | Fast (VirtioFS), but containerized | | `.test` domains + HTTPS | Automatic | Manual (or wire the included Traefik/Caddy) | | Databases, Redis, mail | Herd Pro (paid) or DIY | Included, free, 100+ services | | Production parity | None (native macOS/Windows runtime) | High (same Linux containers as servers) | | Machine footprint | PHP, Nginx, dnsmasq installed globally | Nothing installed; containers are disposable | | Legacy PHP | 7.4+ | 5.6+ | | Price | Free core, Pro is paid | Free, MIT | ## Choose Herd if... - You are on macOS or Windows, mostly solo, mostly Laravel, and iteration speed is everything. - Your services needs are light (SQLite, or you happily pay for Pro). - Production parity is not a concern for your workflow. ## Choose Laradock if... - You develop on (or deploy to) Linux; Herd simply does not run there. - You want your local stack to behave like your production stack, container for container. - You need real infrastructure locally (queues, search, brokers, LLMs) without a subscription. - You want a spotless host machine: clone, run, delete, gone. ## Already on Herd? Migrating takes minutes 1. **Export your databases** from wherever they live today (Herd Pro's MySQL, DBngin, or a local install): `mysqldump -h 127.0.0.1 -u root mydb > backup.sql` 2. **Quit Herd** (its native Nginx holds port 80, which Laradock's web server needs). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start nginx mysql redis workspace` (or `docker compose up -d nginx mysql redis workspace`) 5. **Import the database:** `./laradock exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's `.env`:** `DB_HOST=mysql`, `REDIS_HOST=redis`, credentials from `mysql/defaults.env`. 7. Your site now answers at `http://localhost` instead of `my-app.test`, and `artisan`/`composer` run inside `./laradock workspace`. ## Frequently Asked Questions ### Is Laravel Herd free? Herd's core (PHP version switching, `.test` domains, basic services) is free. Herd Pro adds MySQL/Redis/PostgreSQL management, Xdebug, mail capture, and more, and is a paid subscription. ### Does Laravel Herd run on Linux? No. Herd is available only for macOS and Windows; there is no Linux build. This is one of the main reasons Linux-based teams choose a Docker-based option like Laradock instead. ### Does Herd use Docker? No, Herd installs PHP, Nginx, and DNS resolution natively on your machine rather than running containers. This makes it very fast but means your local environment does not match a containerized production server. ### Can Herd run non-Laravel PHP projects? Yes, despite the name, Herd can serve any PHP project (WordPress, Symfony, plain PHP), not only Laravel apps; Laravel-specific features like Herd Pro's queue/log tooling are just the primary focus. ### How do I switch PHP versions in Herd? Herd lets you switch the PHP version per site from its menu bar app or with `herd php:use 8.3`, and can pin a version per project so switching sites doesn't affect others. See the full landscape, including DDEV, Sail, Lando and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs XAMPP / MAMP Source: https://laradock.io/docs/laradock-vs-xampp ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is XAMPP / MAMP? [XAMPP](https://www.apachefriends.org/) and [MAMP](https://www.mamp.info/) are free, all-in-one installer packages that put Apache, MySQL (or MariaDB), and PHP directly onto your Windows, macOS, or Linux machine. They have been the default way millions of developers got a local PHP environment running since the early 2000s: download one installer, click through a control panel, and your server is running, no command line and no Docker required. This page compares that classic native approach to Laradock, which delivers the same one-download simplicity but runs everything in isolated Docker containers instead of installing software directly on your machine. *XAMPP, MAMP and WAMP served a whole generation of PHP developers: one installer, Apache + MySQL + PHP, done. Laradock keeps that "download and go" simplicity but swaps global installs for disposable containers. This page compares them honestly, and ends with a 10-minute migration guide.* **TL;DR:** pick [XAMPP](https://www.apachefriends.org/)/MAMP only if Docker is not an option on your machine. Otherwise Laradock gives you the same convenience with per-project versions, a production-like stack, and a host machine that stays clean. ## How XAMPP works One installer puts Apache, MySQL and PHP directly on your OS. Projects live in `htdocs/`, services start from the control panel, databases are managed in phpMyAdmin at `localhost/phpmyadmin`. It works, and it is genuinely beginner-friendly. The costs show up over time: **one global PHP version** for every project (switching means reinstalling), config drift between teammates' machines, no isolation (one broken MySQL config affects everything), an environment that looks nothing like your Linux server, and an uninstall that never quite cleans up. ## The same thing with Laradock ```bash cd my-project git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql phpmyadmin ``` ```bash cp .env.example .env docker compose up -d nginx mysql phpmyadmin ``` - Your app: `http://localhost` - phpMyAdmin: `http://localhost:8081` (host `mysql`, user `default`, password `secret`) - Prefer Apache like XAMPP? `./laradock start apache2 mysql phpmyadmin` (or `docker compose up -d apache2 mysql phpmyadmin`). That is the entire difference. Everything runs in containers: each project can have its own PHP (5.6 to 8.5) and its own database, teammates get an identical stack from the same files, and `./laradock remove` leaves your machine exactly as it was. ## Side by side | | **XAMPP / MAMP** | **Laradock** | |---|---|---| | Install | Desktop installer (global Apache/MySQL/PHP) | Nothing (git clone; only Docker itself) | | Start | Control panel buttons | `./laradock start nginx mysql` | | PHP versions | One global (reinstall to switch) | 5.6 to 8.5, per project, via `.env` | | Isolation between projects | None | Full (containers per project) | | Services beyond LAMP | No (Apache + MySQL only) | 100+ (Redis, Postgres, queues, search, mail, LLMs, ...) | | Matches your Linux server | No (native Windows/macOS) | Yes (same containers) | | Team consistency | Everyone configures by hand | Same files = same stack for everyone | | Cleanup | Uninstaller, leftovers linger | `./laradock remove`, zero traces | | Machine footprint | Apache/MySQL/PHP installed globally | Nothing installed on the host | ## Choose XAMPP / MAMP if... - Docker cannot run on your machine (old hardware, company restrictions). - You are teaching absolute beginners where a GUI control panel lowers the barrier. - You have a single small project and native simplicity is all you need. ## Choose Laradock if... - You have more than one project, or more than one PHP version in your life. - You want your local environment to behave like your production server. - You need anything beyond Apache + MySQL: Redis, Postgres, queues, search, mail catchers, each one command away. - You want a machine you can wipe clean in one command. ## Migrate from XAMPP to Laradock in about 10 minutes 1. **Install [Docker Desktop](https://www.docker.com/products/docker-desktop/)** (Windows/macOS) or Docker Engine (Linux). The only installation in this guide. 2. **Export your database** in your OLD phpMyAdmin (XAMPP) as a SQL file. 3. **Move your project out of `htdocs/`** to anywhere you like, and add Laradock next to it: ```bash cd my-project git clone https://github.com/laradock/laradock.git cd laradock && cp .env.example .env ``` 4. **Start your stack:** `./laradock start nginx mysql phpmyadmin` (or `docker compose up -d nginx mysql phpmyadmin`; first run builds for a few minutes, afterwards it starts in seconds). 5. **Import the database** in the NEW phpMyAdmin at `localhost:8081`: create the database, import the file. 6. **Update your app's config:** database host becomes `mysql` (not `localhost`; containers reach each other by service name), user `default`, password `secret` (changeable in `.env`). 7. **Retire the old habits:** | In XAMPP you... | With Laradock you... | |---|---| | Open the control panel and press Start | `./laradock start nginx mysql` | | Stop Apache/MySQL from the panel | `./laradock stop` | | Put projects in `htdocs/` | Keep projects anywhere; set `APP_CODE_PATH_HOST` in `.env` | | Edit `php.ini` | Edit `php-fpm/phpX.Y.ini`, rebuild once | | Switch PHP by reinstalling XAMPP | Change `PHP_VERSION=` in `.env`, rebuild once | | Run `php` / `composer` on your OS | `./laradock workspace` (Linux shell with PHP, Composer, Node, git preinstalled) | | phpMyAdmin at `localhost/phpmyadmin` | phpMyAdmin at `localhost:8081` | ## Frequently Asked Questions ### Is XAMPP free? Yes, XAMPP (Apache Friends) is free and open-source. MAMP has a free tier with a paid MAMP PRO upgrade for more advanced features like multiple virtual hosts. ### Can XAMPP run multiple PHP versions? Not natively; XAMPP installs one global PHP version per installation. Running multiple versions side by side requires installing separate XAMPP copies or a third-party version switcher, whereas Laradock gives every project its own container with its own PHP version out of the box. ### Is XAMPP good for production? No. XAMPP is explicitly designed and documented as a local development tool; its default configuration (open MySQL root password, exposed phpMyAdmin) is not hardened for production use. ### Does XAMPP support Docker? No, XAMPP installs Apache, MySQL, and PHP directly on your operating system; it does not use containers. That is precisely the difference this page compares. ### How do I move a XAMPP project to Docker? Export your database from phpMyAdmin, move your project files out of `htdocs/`, and follow the [step-by-step migration guide](#migrate-from-xampp-to-laradock-in-about-10-minutes) further up this page; it takes about 10 minutes. See the full landscape, including DDEV, Sail, Herd and Lando: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. For the complete setup reference, head to **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Laradock vs Homestead / Vagrant Source: https://laradock.io/docs/laradock-vs-homestead ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Homestead? [Laravel Homestead](https://github.com/laravel/homestead) was Laravel's official pre-built [Vagrant](https://developer.hashicorp.com/vagrant) box: a downloadable virtual machine image, pre-configured with PHP, Nginx, MySQL, and other common services, that you launched with the `vagrant up` command to get a full local Linux server running inside a VM on your machine. It was the standard Laravel local-development recommendation for years, before Docker-based tools took over. This page compares it to Laradock, which offers the same batteries-included philosophy but built on lightweight Docker containers instead of a full virtual machine. *Homestead was Laravel's official answer before containers: a full Ubuntu virtual machine managed by Vagrant, batteries included. Laradock is the same "everything included" philosophy rebuilt on containers: a fraction of the weight, a fraction of the startup time.* **TL;DR:** [Homestead](https://github.com/laravel/homestead) is officially over: the repository was archived in June 2025 and is read-only, with Laravel pointing users to Sail instead. If you are still on it, it keeps working but will never be updated. Laradock is the natural next step: the familiar all-in-one environment, minus the VM tax. ## How Homestead works You install VirtualBox (or another provider) plus Vagrant, add the Homestead box, and describe your machine in `Homestead.yaml`: ```yaml ip: "192.168.56.56" memory: 2048 cpus: 2 folders: - map: ~/code/my-app to: /home/vagrant/my-app sites: - map: my-app.test to: /home/vagrant/my-app/public databases: - my_app ``` Then `vagrant up` (minutes), edit your hosts file for `my-app.test`, and `vagrant ssh` to work inside the VM. PHP, Nginx, MySQL, Redis and more are pre-installed in the box. The tax: the VM permanently reserves gigabytes of RAM, boots slowly, needs full-OS updates, and shared folders are historically the slowest part of the setup. All projects share one VM (or you pay the RAM price several times). ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` That's the same "ssh in and work" feeling Homestead users like. Containers start in seconds, take memory only while running, and each service is isolated instead of sharing one Ubuntu. The `workspace` container gives you the same "one machine with all the tools" experience Homestead users like (PHP, Composer, Node, git inside), without the VM around it. ## Side by side | | **Homestead / Vagrant** | **Laradock** | |---|---|---| | Runs as | Full Ubuntu VM (VirtualBox/Parallels) | Docker containers | | Install | VirtualBox + Vagrant + box download (GBs) | nothing (git clone; only Docker itself) | | Boot time | Minutes | Seconds | | Memory | Reserved up front (2GB+ typical) | Only what running containers use | | Config | `Homestead.yaml` + hosts file | `.env` (+ optional site configs) | | Services | Preinstalled fixed set in the box | 100+, start only what you need | | File sharing | VM shared folders (slow spot) | Docker bind mounts (VirtioFS on Mac) | | Isolation | One VM for everything (typically) | Per-service containers, per-project stacks | | Status | Archived June 2025, read-only, no updates | Actively maintained | ## Stay on Homestead if... - Your team's workflow is deeply wired into Vagrant (snapshots, custom boxes, provisioning scripts). - You specifically need a full VM (kernel modules, systemd services, non-containerizable software). ## Choose Laradock if... - You like Homestead's batteries-included philosophy but not the RAM bill and boot times. - You want per-project isolation instead of one shared VM. - You want your local stack built from the same container technology as modern production. - You want to free VirtualBox-grade resources from your laptop. ## Already on Homestead? Migrating takes minutes 1. **Export your database** from inside the VM: `vagrant ssh` then `mysqldump -uhomestead -psecret my_app > /home/vagrant/my-app/backup.sql` (lands in your synced folder). 2. **Stop the VM:** `vagrant halt` (destroy later with `vagrant destroy` once you are confident). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `docker compose up -d nginx mysql redis workspace` 5. **Import the database:** `docker compose exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's `.env`:** Homestead's `DB_HOST=127.0.0.1` becomes `DB_HOST=mysql`; user `default`, password `secret` (see `mysql/defaults.env`). 7. Remove the `my-app.test` hosts entry or keep it; your site now answers at `http://localhost` (wire nginx site configs for custom domains if you want them back). ## Frequently Asked Questions ### Is Laravel Homestead still maintained? No. The Homestead repository was archived by Laravel in June 2025 and is now read-only; it will not receive further updates. Laravel's documentation points users to Sail instead. ### Is Homestead free? Yes, Homestead itself is free and open-source; you only pay for the resources it reserves on your own machine (RAM, disk) or for a paid VM provider if you use one instead of local VirtualBox. ### Does Homestead use Docker? No, Homestead provisions a full virtual machine via Vagrant (typically using VirtualBox), not Docker containers. That heavier VM model is exactly why the ecosystem, including Laravel itself, moved toward containers. ### Can I still use Homestead in 2026? Yes, existing Homestead boxes continue to work, but since the repository is archived you will not get compatibility fixes for newer host OS versions, VirtualBox releases, or PHP versions. ### What replaced Laravel Homestead? Laravel now recommends [Sail](https://laradock.io/docs/laradock-vs-laravel-sail) for Docker-based local development or [Herd](https://laradock.io/docs/laradock-vs-laravel-herd) for a native macOS/Windows setup. Laradock is a third path for teams who want Homestead's old batteries-included feel without the VM weight. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Lando Source: https://laradock.io/docs/laradock-vs-lando ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Lando? [Lando](https://lando.dev/) is a free, open-source command-line tool that uses Docker to run local development environments from a single configuration file (`.lando.yml`). Similar in spirit to DDEV, it originated in the Drupal community and ships ready-made "recipes" for platforms like Drupal, WordPress, and Laravel, so you describe what kind of project you have and Lando builds the matching Docker setup for you. This page compares it to Laradock, which skips the recipe/generation layer entirely: instead of a tool that builds Docker containers for you, Laradock ships the Docker container definitions directly, ready to run and ready to edit. *Lando is DDEV's closest cousin: a recipe file and a CLI that generate Docker behind the scenes, popular in Drupal and WordPress agency work. Laradock is the opposite philosophy: the Docker files are the product, pre-wired and fully visible.* **TL;DR:** pick [Lando](https://lando.dev/) if your team already standardized on its recipes. Pick Laradock for transparency, a far larger service catalog, and no tool between you and Docker. ## Setting up a Laravel app with Lando Install the Lando binary first, then describe your stack in `.lando.yml` at the project root: ```yaml name: my-app recipe: laravel config: webroot: public php: "8.3" services: cache: type: redis ``` Then: ```bash lando start lando composer install lando artisan migrate ``` Your site is served at `https://my-app.lndo.site`. Day to day you talk to the tool: `lando ssh`, `lando artisan`, `lando db-import`, `lando rebuild` after recipe changes. The compose files Lando generates live in `~/.lando/` and are regenerated; they are not meant to be edited. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Inside the workspace: composer, artisan, node, all ready to go. No binary, no recipe format to learn, no regeneration: the service definitions are plain files in front of you, and the commands are standard Docker Compose. Change PHP with `PHP_VERSION=8.3` in `.env` + rebuild; add any of 100+ services with one `start` command. ## Side by side | | **Lando** | **Laradock** | |---|---|---| | Install | lando binary (+ its own Docker setup) | nothing (git clone) | | Config | `.lando.yml` recipe | `.env` + per-service folders | | URLs | `https://my-app.lndo.site` automatic | `http://localhost` (or wire Traefik/Caddy) | | Services | ~15 supported types | 100+ shipped folders | | Docker files | Generated, hidden | Plain files you own and edit | | Commands | `lando *` vocabulary | standard `docker compose *` | | Frameworks | Recipe-based (Drupal, WordPress, Laravel, ...) | Any PHP project | | Project pace | Slower releases, smaller team than DDEV | Community-maintained since 2015 | | Skills you build | Lando-specific | Transferable Docker | ## Choose Lando if... - Your agency already standardized on Lando recipes and the workflow fits. - You want automatic per-project URLs and HTTPS without touching config. - Your stack fits comfortably inside Lando's supported service types. ## Choose Laradock if... - You want to see and own every Dockerfile and config. - You need services outside Lando's recipe list (brokers, search clusters, LLMs, monitoring). - You prefer plain `docker compose` over another CLI vocabulary. - You want the environment defined by files in your repo tree, not generated state in `~/.lando/`. ## Already on Lando? Migrating takes minutes 1. **Export your database** while Lando still runs: `lando db-export backup.sql.gz && gunzip backup.sql.gz` 2. **Stop Lando:** `lando stop` (keep `.lando.yml` around until you are confident). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `docker compose up -d nginx mysql redis workspace` 5. **Import the database:** `docker compose exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's `.env`:** Lando's Laravel recipe uses `DB_HOST=database`; change it to `DB_HOST=mysql`. Credentials are in `mysql/defaults.env` (user `default`, password `secret`). 7. Your site now answers at `http://localhost` instead of `https://my-app.lndo.site`. ## Frequently Asked Questions ### Is Lando free? Yes, Lando is free and open-source (GPL-3.0), maintained by Tandem/Lando's team, with no paid tier for the core tool. ### Does Lando require rebuilding after every config change? Yes, this is a deliberate Lando design choice: `lando restart` never re-reads `.lando.yml`, only `lando rebuild` does, which recreates containers (while preserving database volumes). It is one of the more common friction points reported by Lando users. ### What frameworks does Lando support? Lando ships built-in "recipes" for many stacks, including Laravel, Drupal, WordPress, generic LAMP/LEMP, and more, each pre-wiring the right services for that framework. ### Can I add custom commands to Lando? Yes, via the `tooling:` section of `.lando.yml`, which lets you define project-specific commands (like `lando php`) that route into the right container; it is one of Lando's most-liked features. ### Is Lando slower than Docker Compose directly? It can feel slower: Lando runs a shared proxy container and additional tooling on top of Docker, and community reports cite multi-minute startup times on some setups, an overhead a direct `docker compose up` (what Laradock uses) does not add. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Dev Containers Source: https://laradock.io/docs/laradock-vs-devcontainers ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What are Dev Containers? [Dev Containers](https://containers.dev/) is an open specification, championed by Microsoft and VS Code, for describing a development environment as a container that your code editor runs inside of. You add a `devcontainer.json` file to a project, and any supporting editor can build that container and reopen your workspace inside it, extensions, terminal, and all. [GitHub Codespaces](https://github.com/features/codespaces) is the cloud-hosted version of the same idea, running that container in the browser instead of on your machine. This page compares that editor-centered approach to Laradock, which is not tied to any editor at all: it defines your project's infrastructure (web server, database, cache, and more), reachable the same way whether you code in VS Code, PhpStorm, Vim, or over SSH. *Dev Containers put your editor inside a container; Laradock puts your infrastructure inside containers. They answer different questions, compete on some ground, and combine surprisingly well.* **TL;DR:** pick [Dev Containers](https://containers.dev/) / Codespaces if your team lives in VS Code and wants one-click onboarding. Pick Laradock if the environment should belong to the project rather than the editor. Best of both: point your `devcontainer.json` at Laradock (shown below). ## How Dev Containers work A `.devcontainer/devcontainer.json` in your repo describes the container your editor should work inside: ```json { "name": "my-app", "image": "mcr.microsoft.com/devcontainers/php:1-8.3", "features": { "ghcr.io/devcontainers/features/node:1": {} }, "forwardPorts": [8000], "postCreateCommand": "composer install" } ``` VS Code's "Reopen in Container" builds it and moves your terminal, extensions and debugger inside; GitHub Codespaces runs the same thing in the cloud, so a new teammate codes in minutes without installing anything. The limits: it is editor-centric (the experience belongs to VS Code and, partially, JetBrains), and a single image only gets you PHP. The moment you need MySQL, Redis or a queue, `devcontainer.json` must reference a `docker-compose.yml` that you write and maintain yourself; Dev Containers standardize where your editor runs, not what your stack contains. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace ``` The stack is defined by the project and runs identically no matter what you code in: VS Code, PhpStorm, Vim, or SSH from another machine. The compose wiring Dev Containers would ask you to write is exactly the part Laradock ships pre-built, 100+ services included. ## Side by side | | **Dev Containers / Codespaces** | **Laradock** | |---|---|---| | Centered on | The editor (VS Code first) | The project's infrastructure | | Defines | Where your editor + tools run | Your full multi-service stack | | Multi-service stacks | Via a compose file you write | Pre-wired, 100+ services | | Editor support | VS Code excellent, JetBrains partial, others degraded | Any editor, terminal, or SSH | | Cloud option | Codespaces (paid beyond free tier) | Any Docker host | | Onboarding | One click (best in class) | `./laradock setup`, Enter through the wizard | | Config | `devcontainer.json` (+ compose underneath) | `.env` + per-service folders | | Lock-in | Spec is open; experience is VS Code-shaped | None (plain compose) | ## Choose Dev Containers if... - Your team is all-in on VS Code and wants zero-install, one-click onboarding. - You want Codespaces so contributors never run anything locally. - Your stack is simple enough that one image (plus maybe a database) covers it. ## Choose Laradock if... - Your team uses mixed editors, or you refuse to couple infrastructure to an editor. - You need a real multi-service stack without hand-writing the compose file underneath. - You want the same environment reachable from a terminal, CI, or another machine, no editor involved. ## Best of both: point your devcontainer at Laradock You do not have to choose. Let Laradock define the stack and Dev Containers define the editor experience: with Laradock cloned inside your project, put this in `.devcontainer/devcontainer.json`: ```json { "name": "my-app", "dockerComposeFile": "../laradock/docker-compose.yml", "service": "workspace", "workspaceFolder": "/var/www", "runServices": ["nginx", "mysql", "redis", "workspace"] } ``` "Reopen in Container" now drops VS Code into Laradock's `workspace` container (PHP, Composer, Node, git preinstalled) with your whole service stack running around it: one-click onboarding on top, transparent pre-wired infrastructure underneath. ## Frequently Asked Questions ### Is the Dev Containers spec free? Yes, the [Dev Containers specification](https://containers.dev/) is open and free to use in any editor that implements it. GitHub Codespaces, which runs Dev Containers in the cloud, is free for a limited monthly quota and paid beyond that. ### Do Dev Containers work outside VS Code? Partially. VS Code has the most complete implementation; JetBrains IDEs support Dev Containers with some feature gaps; other editors have little to no native support, since the ecosystem and tooling were built around VS Code first. ### Can Dev Containers run a multi-service stack like MySQL and Redis? Yes, but only if you write a `docker-compose.yml` for it yourself and reference it from `devcontainer.json` via `dockerComposeFile`; the spec does not ship pre-wired services the way Laradock does. ### Can I use Laradock inside a Dev Container? Yes. Point your `devcontainer.json`'s `dockerComposeFile` at Laradock's `docker-compose.yml` and set `service` to `workspace`; see the [combo setup](#best-of-both-point-your-devcontainer-at-laradock) above for the exact config. ### What is GitHub Codespaces? Codespaces is GitHub's cloud-hosted implementation of the Dev Containers spec: it builds your `devcontainer.json` on GitHub's infrastructure so contributors can start coding in a browser with zero local setup. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Plain Docker Compose Source: https://laradock.io/docs/laradock-vs-docker-compose ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What does "your own Docker Compose" mean? [Docker Compose](https://docs.docker.com/compose/) is the standard, official tool built into Docker for defining and running a multi-container application from a single YAML file. "Writing your own" means creating that `docker-compose.yml` (or several service files) completely from scratch for your PHP project: choosing base images, writing the PHP Dockerfile, wiring the web server to PHP, and so on, with no starter kit or framework involved. This page compares that from-scratch path to Laradock, which is not a different technology at all, it is the exact same Docker Compose, just already written, tested, and maintained for 100+ services since 2015. *This is the closest comparison of all, because Laradock IS plain Docker Compose: the same files, the same commands, just already written. The question is only whether you write the wiring yourself or start from wiring that thousands of teams have battle-tested since 2015.* **TL;DR:** roll your own if your stack is tiny and you enjoy the craft; it is real engineering fun. Pick Laradock to skip days of wiring and keep 100% of the control, because the result is the same kind of files, fully yours to edit, with zero tool lock-in either way. ## Writing it yourself The honest inventory of a from-scratch PHP environment: ```yaml # docker-compose.yml, the easy 20% services: app: build: ./php # <- the hard 80% lives in this Dockerfile volumes: - ../:/var/www nginx: image: nginx:alpine ports: ["80:80"] volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf - ../:/var/www mysql: image: mysql:8.4 environment: MYSQL_ROOT_PASSWORD: root volumes: - dbdata:/var/lib/mysql volumes: dbdata: ``` The compose file is the quick part. The real work is the PHP image: choosing a base, compiling extensions (gd, intl, opcache, redis, xdebug, ...), matching versions, getting file permissions right between host and container (the classic macOS/Linux UID dance), wiring nginx to php-fpm, adding a usable shell with Composer and Node, and then maintaining all of it as PHP versions and base images move underneath you. Plan on days for the first working version and recurring upkeep forever. ## The same thing with Laradock ```bash git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace ``` That is the identical architecture you would have built (nginx to php-fpm, per-service containers, named volumes, a dev shell), already wired, with ~100 more services ready behind the same command. The PHP images come with 50+ extensions as one-line toggles (`PHP_FPM_INSTALL_GD=true`), permissions are solved, and every file is in front of you: [mysql/compose.yml](https://github.com/laradock/laradock/blob/master/mysql/compose.yml), `php-fpm/Dockerfile`, `nginx/sites/`. Editing them IS the workflow; there is no abstraction to fight. ## Side by side | | **Your own Compose** | **Laradock** | |---|---|---| | Time to first working stack | Days (PHP image is the hard part) | Minutes | | Control | Total | Total (same files, pre-written) | | Commands | `docker compose *` | `docker compose *` (identical) | | PHP extensions | You compile them | One-line toggles, 50+ ready | | Services available | What you write | 100+ shipped | | Maintenance | Yours forever | Community-maintained, `git pull` | | Battle-testing | Your projects | Thousands of teams since 2015 | | Lock-in | None | None (it is just compose files) | ## Write your own if... - Your stack is genuinely tiny (one container, SQLite) and will stay that way. - You want the learning exercise; building a PHP image once teaches you a lot. - Your production compose files must be authored in-house line by line, and dev must mirror them exactly. ## Pick Laradock if... - You want the result of that work today, with the same level of control at the end. - You need more than a couple of services; nobody hand-writes 100 service definitions. - You would rather maintain a `git pull` than a PHP Dockerfile as versions move. - You want your own future customizations to start from a proven baseline instead of a blank file. ## Already have your own compose file? Adopt Laradock gradually Nothing forces a big bang; it is all just Compose: 1. **Run Laradock alongside** your existing setup for the services you are missing: `./laradock start elasticsearch rabbitmq` (or `docker compose up -d elasticsearch rabbitmq`) from the laradock folder while your own stack keeps running (watch for port overlaps; override any port with one line in Laradock's `.env`). 2. **Steal what you like:** every service definition is a small readable file (`/compose.yml` + `/defaults.env`); copy patterns or whole folders into your setup, MIT-licensed. 3. **Or move in fully:** point `APP_CODE_PATH_HOST` at your code, start your services, and bring your custom containers with you; adding one is a folder with a `compose.yml` plus one `include` line in the root file. ## Frequently Asked Questions ### Is writing my own Docker Compose file hard for PHP? The compose file itself is easy; the hard part is the PHP image: compiling the right extensions, matching versions, solving host/container file-permission mismatches, and wiring nginx to php-fpm correctly. That is the work Laradock has already done. ### Is Laradock just Docker Compose? Yes, essentially. Laradock IS a set of plain `docker-compose.yml`/`compose.yml` files; there is no proprietary format or hidden abstraction layer. You use the exact same `docker compose` commands you would use with a hand-written setup. ### Can I mix my own services with Laradock's? Yes, either run Laradock alongside your existing compose stack for the services you're missing, or copy individual service folders (`compose.yml` + `defaults.env`) into your own project; every file is MIT-licensed and self-contained. ### Do I need to know Docker Compose to use Laradock? Basic familiarity helps but is not required to get started (`./laradock start nginx mysql`, or `docker compose up -d nginx mysql`, is the whole first step); however, because Laradock is just compose files, learning Docker Compose while using it transfers directly to any future project. ### What Docker Compose version does Laradock require? Compose v2.20 or newer, because the root `docker-compose.yml` uses the `include` directive to pull in each service's own compose file. Check your version with `docker compose version`. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Installing PHP Manually Source: https://laradock.io/docs/laradock-vs-manual-install ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What does "installing PHP manually" mean? This is the oldest approach of all: installing PHP, a web server, and a database directly onto your operating system yourself, using your system's package manager, `brew` on macOS, `apt` on Ubuntu/Debian, `dnf` on Fedora, and configuring them by hand. No installer bundle, no virtual machine, and no containers involved; everything runs natively as processes on your machine. This page compares that bare-metal approach to Laradock, which gives you the same native-feeling simplicity (still just a `git clone` and one command) but runs every service in an isolated, disposable Docker container instead of installing anything permanently on your machine. *The no-tools path: `brew install` (or `apt install`) PHP, MySQL, Nginx straight onto your machine and wire them yourself. Plenty of seniors work this way and it is genuinely fast. This page is the honest ledger of what it costs, against running the same stack in containers.* **TL;DR:** stay bare-metal if you run one project on one machine and know your OS well. Pick Laradock the moment a second project, a second PHP version, a second machine, or a second teammate enters the picture. ## The manual way ```bash # macOS flavor; apt/dnf equivalents on Linux brew install php@8.4 mysql redis nginx composer node brew services start mysql brew services start redis brew services start nginx # then: nginx server block, php-fpm pool config, hosts entry, per-project tweaks... ``` It boots fast and runs at native speed. The recurring costs: **one global PHP** unless you add version managers on top, config scattered across `/opt/homebrew/etc` or `/etc`, `brew upgrade` occasionally breaking every project at once, each teammate hand-building a slightly different machine, an environment that does not resemble your Linux server, and no clean way back; uninstalls leave traces everywhere. ## The same thing with Laradock ```bash cd my-project git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Inside the workspace: php, composer, node, git, all inside. Same stack, containerized: per-project PHP versions (5.6 to 8.5) side by side, configs in one visible folder tree instead of across your OS, teammates get identical environments from the same files, and `./laradock remove` returns your machine to exactly how it was. ## Side by side | | **Manual install (brew/apt)** | **Laradock** | |---|---|---| | Raw speed | Native (fastest) | Container overhead (small; VirtioFS on Mac) | | PHP versions | One global (or juggle version managers) | Per project, `.env` one-liner | | Config location | Scattered across the OS | One folder tree, all visible | | Breakage risk | `brew upgrade` can break everything at once | Rebuild one container at a time | | Team consistency | Every machine hand-built | Same files = same stack | | Extra services | Install each one globally | 100+, one command each, disposable | | Production parity | None (macOS/Windows native) | High (Linux containers) | | Uninstall | Leftovers forever | `down` + delete folder, zero traces | ## Stay manual if... - One project, one machine, and native performance genuinely matters to your workflow. - You administer your OS confidently and enjoy owning the config. - Docker is not allowed or not available in your environment. ## Choose Laradock if... - You juggle multiple projects or PHP versions; this is where bare-metal collapses first. - You want your local stack to behave like your Linux production server. - You onboard teammates and want "clone and run" instead of a setup document. - You want experiments (a queue, a search engine, an LLM) to be disposable, not installed. ## Already bare-metal? Migrating takes minutes 1. **Export your databases** from the local MySQL: `mysqldump -h 127.0.0.1 -u root my_db > backup.sql` 2. **Stop the native services** so ports 80/3306/6379 free up: `brew services stop nginx mysql redis` (uninstall later, once you are confident). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start nginx mysql redis workspace` (or `docker compose up -d nginx mysql redis workspace`) 5. **Import the database:** `./laradock exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's config:** `DB_HOST=127.0.0.1` becomes `DB_HOST=mysql`; credentials in `mysql/defaults.env`. 7. Your CLI life moves inside: `./laradock workspace` has PHP, Composer and Node matching the container versions, not whatever brew last upgraded to. ## Frequently Asked Questions ### Is installing PHP with brew or apt faster than Docker? Raw execution speed is typically faster natively since there is no container overhead, but the setup and switching-versions time usually goes the other way: reinstalling or juggling version managers for a second PHP version takes longer than `docker compose up -d` with a different `PHP_VERSION` in `.env`. ### Can I run multiple PHP versions with Homebrew? Yes, with extra tooling: Homebrew installs one linked PHP version at a time; running several side by side requires a version manager (like `phpbrew` or manually juggling `brew unlink`/`brew link`), which is exactly the friction Docker containers remove by isolating each project. ### Is a manual PHP install good for a team? It works, but every teammate has to reproduce the same steps by hand, and small differences in versions or installed extensions across machines are a common source of "works on my machine" bugs. A shared Laradock setup gives every teammate the identical environment from the same files. ### Does a manual install match my production server? Usually not exactly: a native macOS or Windows PHP/Nginx/MySQL install behaves differently from the Linux containers most production servers run. Docker-based setups like Laradock use the same container technology in dev and prod. ### How do I clean up a manual PHP install? You typically need to uninstall each package individually (`brew uninstall php mysql nginx`) and manually remove leftover config and data directories; with Laradock, `docker compose down` plus deleting the folder leaves no trace. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Help Source: https://laradock.io/docs/help ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Something not working right? You're not the first to hit it, most Laradock setups run into the same handful of snags: a blank Laravel page, a port already taken, MySQL refusing to connect. Below are the common problems and their fixes, organized by symptom and OS. Find the one that matches what you're seeing and work through it step by step. ![Docker Image](https://laradock.io/img/laradock/laradock-abstract-thinner.jpg) ## Get Help Can't find your issue below? Reach out: - Need something directly? **mahmoud@zalt.me** - Security vulnerabilities: follow the [Security Policy](https://github.com/laradock/laradock/blob/master/SECURITY.md). ## Upgrading ### I pulled the latest and see a huge diff or git conflicts Nothing is broken. Laradock's files were reorganized, the one big `docker-compose.yml` and `.env.example` became small per-service files, but everything you run is unchanged and your `.env` is left untouched. The [Upgrade Guide](https://laradock.io/docs/upgrade-guide) explains the change, resolves any conflict in one step, and includes a copy-paste prompt that lets an AI agent migrate your setup for you. ## Pages & display ### I see a blank (white) page instead of the Laravel welcome page Fix the storage permissions. Run this from your Laravel project root: ```bash sudo chmod -R 777 storage bootstrap/cache ``` ### I see "Welcome to nginx" instead of my Laravel app Use `http://127.0.0.1` instead of `http://localhost` in your browser. ## Ports & networking ### I get "address already in use" or "port is already allocated" Another program on your host is already using one of the ports Laradock needs (22, 80, 443, 3306, etc.). Stop that program, or change the port in your `.env` (for example `NGINX_HOST_HTTP_PORT`). ### I get an NGINX 404 Not Found on Windows Docker can't see your project files because the drive is not shared: - **WSL 2 backend (default):** keep your project inside your WSL 2 distro's filesystem, or enable the distro under Docker Desktop β†’ **Settings β†’ Resources β†’ WSL Integration**. - **Hyper-V backend:** enable your project's drive under Docker Desktop β†’ **Settings β†’ Resources β†’ File Sharing**. Then restart Docker Desktop. ## Databases ### I get MySQL connection refused This usually means your app is not connecting to the MySQL container. Set `DB_HOST` in your Laravel `.env` to the MySQL container name: ```dotenv DB_HOST=mysql ``` ### I changed the database name, user, or password but nothing happens MySQL/PostgreSQL only read those values the **first** time the data volume is created. After that the data persists in `DATA_PATH_HOST` (default `~/.laradock/data`), so later `.env` changes are ignored. To start fresh, stop the containers and delete that database's data folder, then bring it back up: ```bash ./laradock remove ``` ```bash docker compose down ``` ```bash rm -rf ~/.laradock/data/mysql # or /postgres, /mariadb, etc. ``` ```bash ./laradock start mysql ``` ```bash docker compose up -d mysql ``` :::warning This deletes the database's local data. Back it up first if you need it. ::: ### The server requested authentication method unknown to the client MySQL 8 uses `caching_sha2_password` by default, which some older clients and drivers don't support. Connect through the workspace and switch the user to the legacy method: ```sql ALTER USER 'default'@'%' IDENTIFIED WITH mysql_native_password BY 'secret'; FLUSH PRIVILEGES; ``` ### I can't connect to or log in to phpMyAdmin / pgAdmin Use the **container name** as the server/host, not `localhost`: - phpMyAdmin β†’ server `mysql` (or `mariadb`), with the `MYSQL_USER` / `MYSQL_PASSWORD` from your `.env`. - pgAdmin β†’ host `postgres`, with your `POSTGRES_USER` / `POSTGRES_PASSWORD`. ## Build, mirrors & timing ### Package mirrors are slow or the build hangs fetching sources Common when your network is far from the default mirrors (for example in China): - If an image build hangs while fetching Alpine/Debian package indexes, set `CHANGE_SOURCE=false` in your `.env` and rebuild. - To use faster Composer and NPM mirrors, add these to your `.env`: ```dotenv WORKSPACE_NPM_REGISTRY=https://registry.npmmirror.com WORKSPACE_COMPOSER_REPO_PACKAGIST=https://packagist.phpcomposer.com ``` ### The time in my services does not match the current time 1. Make sure you have [changed the timezone](https://laradock.io/docs/environment#change-the-timezone). 2. Rebuild and restart the containers: `./laradock rebuild ` then `./laradock restart ` (or `docker compose up -d --build `). ## macOS & Apple Silicon ### The apache2 container won't start on Apple Silicon (M1/M2) 1. Set `APACHE_FOR_MAC_M1=true` in your `.env`. 2. Rebuild the image: `./laradock rebuild apache2` (or `docker compose build apache2`). ### Everything is slow on macOS File-system sync between the host and containers is the usual cause. Enable **VirtioFS** in Docker Desktop β†’ **Settings β†’ General β†’ Choose file sharing implementation**, and give Docker Desktop enough CPU/RAM under **Settings β†’ Resources**. ================================================================ # Ecosystem Source: https://laradock.io/docs/related-projects ================================================================ Laradock has inspired a rich ecosystem of community-built tools that extend, port, or simplify how you work with it. The projects below are grouped by what they do, and built and maintained by the community. Explore them to find helpers that fit your workflow. Discover [1.5K+ community projects](https://github.com/search?q=laradock&type=repositories&s=stars&o=desc) built around Laradock. ![Docker Image](https://laradock.io/img/laradock/laradock-abstract-thinner.jpg) ## Inspired by Laradock Laradock's model, one repo, one `.env`, a menu of pre-configured containers, ported to other languages and frameworks. * [Dockery](https://github.com/taufek/dockery): Laradock for Ruby. (by [Taufek Johar](https://github.com/Taufek)) * [RubyDev Dock](https://github.com/scudelletti/rubydev-dock): Laradock for Ruby. (by [Diogo Scudelletti](https://github.com/scudelletti)) * [NoDock](https://github.com/Osedea/nodock): Laradock for NodeJS. (by [Osedea](https://github.com/Osedea)) * [Laradock Multi](https://github.com/bagart/laradock-multi): Laradock for PHP & NodeJS. (by [BAG Art](https://github.com/bagart)) * [Wordpress Laradock](https://github.com/shov/wordpress-laradock): Laradock for Wordpress. (by [Alexandr Shevchenko](https://github.com/shov)) * [Yii2 Laradock](https://github.com/ydatech/yii2-laradock): Laradock for Yii2. (by [Yuda Sukmana](https://github.com/ydatech)) * [MageDock](https://github.com/ojhaujjwal/magedock): Laradock for Magento. (by [Ujjwal Ojha](https://github.com/ojhaujjwal)) * [Odoodock](https://github.com/aoltra/odoodock): Laradock for Odoo. (by [aoltra](https://github.com/aoltra)) * [Docker Codeigniter](https://github.com/sebastianlzy/docker-codeigniter): Laradock for Codeigniter. (by [Sebastian](https://github.com/sebastianlzy)) ## CLIs & GUIs Tools that wrap Laradock's `docker-compose` commands behind a friendlier CLI or a full desktop GUI. * [DECK](https://github.com/sfx101/deck): A local web development studio and GUI alternative to Docker Desktop, evolved from the original Laradock GUI. (by [Subhadip Naskar](https://github.com/sfx101)) * [Laradock Manager](https://github.com/Lyimmi/laradock-manager): A simple app for managing Laradock containers. Made with wails.app (go & vue.js & vuetify). (by [ZΓ‘mbΓ³ Levente](https://github.com/Lyimmi)) * [Laradock CLI](https://github.com/lorinlee/laradock-cli): A CLI for managing Laradock. (by [Lorin Lee](https://github.com/lorinlee)) * [Laradock CLI](https://github.com/harlan-zw/laradock-cli): A CLI for managing Laradock. (by [Harlan Wilton](https://github.com/harlan-zw)) * [Laradock CLI](https://github.com/tonysm/laradock-cli): Laradock CLI helper. (by [Tony Messias](https://github.com/Tonysm)) * [Laradock Env](https://github.com/bagart/laradock_env): A wrapper with commands for managing Laradock. (by [BAG Art](https://github.com/bagart)) * [Lara Query](https://github.com/abekdwight/laraQuery): Easy Laradock CLI. (by [Okita kamegoro](https://github.com/abekdwight)) * [Laradock Makefile](https://github.com/bazavlukd/laradock-makefile): Makefile with some useful commands for Laradock. (by [Dmitry Bazavluk](https://github.com/bazavlukd)) ## Infrastructure & Ops Taking Laradock's containers beyond local dev: orchestration, deployment, and monitoring. * [Laradock Kubernetes Helm Chart](https://github.com/engineering-bjs/laradock-kubernetes): A Helm Chart for deploying Laradock-style Laravel environments on Kubernetes, with cron jobs and a Redis queue/session setup. (by [Anish Dhanka](https://github.com/engineering-bjs)) * [Ansible Laradock Kubernetes](https://github.com/sifat-rahim-zz/ansible-laradock-kubernetes): Ansible playbook to setup docker containers for Laravel apps using Laradock. (by [Sifat Rahim](https://github.com/sifat-rahim-zz)) * [Monitor Laradock](https://github.com/zeroc0d3/monitor-laradock): Laradock Monitoring Tools (using Grafana). (by [Dwi Fahni Denni](https://github.com/zeroc0d3)) * [Laradock Build](https://github.com/dockerframework/laradock-build): Docker builder & running script for Laradock. (by [Docker Framework](https://github.com/dockerframework)) ## Add-ons & Utilities Small helpers that drop into an existing Laradock setup rather than replacing it. * [Laradock Change PHP](https://github.com/abdulwahabkhan1/laradock-change-php): Shell script to switch the PHP version in a Laradock setup. (by [Abdul Wahab](https://github.com/abdulwahabkhan1)) * [PHP 5.3 for Laradock](https://github.com/ustych/php5.3-laradock): Legacy PHP 5.3 php-fpm/workspace images to drop into a Laradock setup. (by [Maksym Ustych](https://github.com/ustych)) ## Variants & Custom Builds Reworked or trimmed-down versions of Laradock itself. * [Laradock Lite](https://github.com/yangliuyu/laradock-lite): A Docker based laravel development environment with minimal dependencies. (by [Liu Yang](https://github.com/yangliuyu)) * [Stylemix's Laradock](https://github.com/stylemix/laradock): Alternate laradock for multiproject purpose. (by [Stylemix LLC](https://github.com/stylemix)) * [Klaradock](https://github.com/poyhsiao/Klaradock): A customized Laradock. (by [Kim Hsiao](https://github.com/poyhsiao)) * [fyvri/laradock](https://github.com/fyvri/laradock): A customizable Laravel environment with Docker Compose, PHP-FPM, and Nginx, built for easy adjustment of PHP versions and dependencies. (by [Azis Alvriyanto](https://github.com/fyvri)) ## Guides, Examples & Starter Kits Tutorials and starter projects that show Laradock in use. * [Laravel Laradock PHPStorm](https://github.com/LarryEitel/laravel-laradock-phpstorm): Guide for configuring PHPStorm for remote debugging with Laravel & Laradock. (by [Larry Eitel](https://github.com/LarryEitel)) * [Laradock Sample](https://github.com/tadaken3/laradock-sample): Install Laravel with Laradock. (by [Tadaken3](https://github.com/tadaken3)) * [Laradock Crudbooster](https://github.com/nutellinoit/laradock-crudbooster): Docker compose & Kubernetes solution to build apps with crudbooster & Laradock. (by [Samuele Chiocca](https://github.com/nutellinoit)) * [Microservices with Laradock](https://github.com/ahmedalaahagag/microservices-php-project): Example project demoing a Lumen microservices architecture (API gateway + services) running on Laradock. (by [Ahmed Hagag](https://github.com/ahmedalaahagag)) * [Laravel Boilerplate](https://github.com/casivaagustin-zz/laravel-boilerplate): A boilerplate with support for JWT, built with Laradock, Infyom and Laratrust. (by [Casiva Agustin](https://github.com/casivaagustin-zz)) :::tip Feel free to submit a PR for listing your project here. ::: ================================================================ # Contributions Source: https://laradock.io/docs/contributing ================================================================ Welcome, Laradock is entirely community-driven, and that means it runs on people like you. Maybe you found a bug, want a new container supported, or you're ready to submit your first pull request, whatever brought you here, this page walks through how to do it well. Pick the section below that matches what you're trying to do. ![Docker Image](https://laradock.io/img/laradock/laradock-abstract-thin.jpg) ## Have a Question Have a question, found a problem, or need something? **mahmoud@zalt.me** Or open an [Issue](https://github.com/laradock/laradock/issues) on GitHub (it will be labeled as `Question`) so others can benefit from the answer. ## Found an Issue If you have an issue or you found a typo in the documentation, you can help us by opening an [Issue](https://github.com/laradock/laradock/issues). **Steps to do before opening an Issue:** 1. Before you submit your issue search the archive, maybe your question was already answered couple hours ago (search in the closed Issues as well). 2. Decide if the Issue belongs to this project or to [Docker](https://github.com/docker) itself! or even the tool you are using such as Nginx or MongoDB... If your issue appears to be a bug, and hasn't been reported, then open a new issue. *This helps us maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.* ## Want a Feature You can request a new feature by submitting an [Issue](https://github.com/laradock/laradock/issues) (it will be labeled as `Feature Suggestion`). If you would like to implement a new feature then consider submitting a Pull Request yourself. ## Update the Documentation (Site) Laradock uses [Docusaurus](https://docusaurus.io/) as its documentation site generator. Navigate to the `DOCUMENTATION/docs` directory to locate and edit the Markdown files for each section of the documentation. :::note Each folder under `docs` is a sidebar section, ordered by the `sidebar_position` field in each file's frontmatter. The site is auto-generated and deployed to the `gh-pages` branch by GitHub Actions whenever changes are pushed to `master`. ::: ### Host the Documentation Locally 1. Make your changes in the `DOCUMENTATION/docs` directory. 2. Navigate to `DOCUMENTATION/`. 3. Run the following command to start a local Docusaurus server: ``` npm run start ``` 4. Visit [http://localhost:3000/](http://localhost:3000/) to view the documentation site locally. This setup will allow you to preview your changes in real time. ## Support new Software (Add new Container) * Fork the repo and clone the code. * Create folder as the software name (example: `mysql` - `nginx`). * Add your `Dockerfile` in the folder "you may add additional files as well". * Add the container definition as `compose.yml` inside your folder, and register it with an `include` entry in the root `docker-compose.yml`. * Make sure you follow the same code/comments style. * Add the environment variables, pre-filled with working defaults, as `defaults.env` inside your folder (only truly shared variables belong in `.env.example`). * **MOST IMPORTANTLY** update the `Documentation`, add as much information. * Submit a Pull Request, to the `master` branch. ## Edit supported Software (Edit a Container) * Fork the repo and clone the code. * Open the software (container) folder (example: `mysql` - `nginx`). * Edit the files. * Make sure to update the `Documentation` in case you made any changes. * Submit a Pull Request, to the `master` branch. ## Edit Base Image * Open any dockerfile, copy the base image name (example: `FROM phusion/baseimage:latest`). * Search for the image in the [Docker Hub](https://hub.docker.com/search/) and find the source.. *Most of the images in Laradock are official images; these projects live in other repositories and are maintained by other organizations.* :::note Laradock has two base images, mainly made to speed up the build time on your machine. Each lives in its own repository: * [`laradock/workspace`](https://github.com/laradock/workspace), the all-in-one dev shell. * [`laradock/php-fpm`](https://github.com/laradock/php-fpm), the PHP runtime. See each repo's `AGENTS.md` for how it builds. ::: * Find the dockerfiles, edit them and submit a Pull Request. * When updating a Laradock base image (`Workspace` or `php-fpm`), ask a project maintainer "Admin" to build a new image after your PR is merged. :::note After the base image is updated, every dockerfile that uses that image, needs to update his base image tag to get the updated code. ::: ## Submit Pull Request Instructions ### 1. Before Submitting a Pull Request (PR) Always Test everything and make sure its working: - Pull the latest updates (or fork if you don’t have permission) - Before editing anything: - Test building the container (docker compose build --no-cache container-name) build with no cache first. - Test running the container with some other containers in a real app and see if everything is working fine. - Now edit the container (edit section by section and test rebuilding the container after every edited section) - Testing building the container (docker compose build container-name) with no errors. - Test it in a real App if possible. ### 2. Submitting a PR Consider the following guidelines: * Search [GitHub](https://github.com/laradock/laradock/pulls) for an open or closed Pull Request that relates to your submission. You don't want to duplicate efforts. * Make your changes in a new git branch: ```shell git checkout -b my-fix-branch master ``` * Commit your changes using a descriptive commit message. * Push your branch to GitHub: ```shell git push origin my-fix-branch ``` * In GitHub, send a pull request to `laradock:master`. * If we suggest changes then: * Make the required updates. * Commit your changes to your branch (e.g. `my-fix-branch`). * Push the changes to your GitHub repository (this will update your Pull Request). :::note If the PR gets too outdated we may ask you to rebase and force push to update the PR: ```shell git rebase master -i git push origin my-fix-branch -f ``` ::: :::warning Squashing or reverting commits and forced push thereafter may remove GitHub comments on code that were previously made by you and others in your commits. ::: ### 3. After your PR is merged After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository: * Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: ```shell git push origin --delete my-fix-branch ``` * Check out the master branch: ```shell git checkout master -f ``` * Delete the local branch: ```shell git branch -D my-fix-branch ``` * Update your master with the latest upstream version: ```shell git pull --ff upstream master ``` ## Happy Coding :) ================================================================ # The Laradock CLI Source: https://laradock.io/docs/cli ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; # The Laradock CLI The Laradock CLI is the **easy, fast way to get your whole PHP environment running**, without touching Docker or learning any of its commands and flags. You clone Laradock, run one command, answer a couple of simple questions, and your stack (web server, PHP, database, and anything else you need) is up and ready. From then on you manage everything in plain English: `start`, `stop`, `restart`, `logs`. That's it. No `docker`, no `-d`, no `-f`, nothing to memorize. For most people, this is all you'll ever need. ## Get started in one command ```bash git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start ``` The first time, `start` walks you through a quick setup (it even detects your project and pre-fills every answer, so you can just press Enter), then launches your stack. After that, `./laradock start` simply starts what you chose. ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace ``` No wizard, no detection, just plain Compose: copy the env file, then start whichever services your project needs (swap the list for what applies to you). Open `http://localhost` and you're running. ## The commands you'll actually use Everything is a normal English word. `[services]` is optional, name one or more (like `mysql` or `nginx mysql`), or leave it off to act on your whole stack. | Command | What it does | |---|---| | `./laradock start [services]` | Start your stack (or just the services you name). First run: sets you up first. | | `./laradock stop [services]` | Stop it. Your data is kept. | | `./laradock restart [services]` | Restart it. | | `./laradock remove [services]` | Delete the containers. Your data on disk is kept. | | `./laradock rebuild [services]` | Apply a version or config change you made. | | `./laradock logs [services]` | Show recent logs (handy when something misbehaves). | | `./laradock set KEY=VALUE` | Change a setting without opening an editor, e.g. `./laradock set REDIS_PORT=16379`. Writes it to your `.env`, then tells you (or offers) how to apply it. | | `./laradock settings [service]` | See every setting a service accepts with its current value (`./laradock settings mysql`), or run it bare to list everything you've customized. | | `./laradock unset KEY` | Undo a change, back to the shipped default. | | `./laradock edit [service] [file]` | Open your `.env` in your editor. Name a service to open its `Dockerfile` (`./laradock edit mysql`), or any of its files (`./laradock edit mysql my.cnf`); it then tells you the command that applies your change. | | `./laradock enter ` | Open a terminal inside a container, e.g. `./laradock enter mysql`. | | `./laradock exec ` | Run one command inside a container without entering it, e.g. `./laradock exec workspace php artisan migrate`. | | `./laradock workspace` | Open the dev shell: `php`, `composer`, `node`, `git`, all preinstalled. | | `./laradock test [args]` | Run your test suite inside the workspace. Auto-detects the runner (`artisan test`, then Pest, then PHPUnit); extra args pass through, e.g. `./laradock test --filter=Orders`. | | `./laradock db` | Open a SQL shell in your running database, credentials handled for you. Auto-detects MySQL, MariaDB, or PostgreSQL. | | `./laradock open [ui]` | Open your app in the browser. Name a UI to open that instead: `./laradock open mailpit` (also `phpmyadmin`, `adminer`), or pass a full URL. | | `./laradock share` | Get a temporary public URL for your local site, handy for previews and webhook testing. Uses `cloudflared` or `ngrok` if installed. | | `./laradock info` | What's running: URLs, ports, and passwords. | | `./laradock doctor` | Check for common problems and tell you how to fix them. | | `./laradock ship [tag] [--push]` | Build a hardened production image of your app to deploy anywhere (server, Kubernetes, any cloud). On Apple Silicon it builds `linux/amd64` by default. See [Deploy to Production](https://laradock.io/docs/production). | | `./laradock setup` | Re-run the setup questions any time. | Flags: `--yes` (`-y`) accepts every default (handy for scripts/CI). `NO_COLOR` is honored. On Windows, run it from WSL or Git Bash (the same environments Docker Desktop uses). ## The setup wizard Setup asks a few simple questions, and **every one is pre-answered with a sensible default**, so pressing Enter straight through gives you a working stack. Each question also shows a short plain-English note explaining what it is and why the default is a safe choice. It first detects your project (Laravel, WordPress, Symfony, Drupal, or plain PHP) and pre-selects it. Each of the ten steps gets its own screen: a header telling you where you are, a plain-English note on what you're choosing and why the default is safe, the full list of what's available (grouped), then a picker. Arrow keys to move, type to filter, Enter to choose. 1. **Project** (search the full 100+ catalog), 2. **PHP version**, 3. **PHP runtime** (defaults to `php-fpm`, the standard choice), 4. **Web server**, 5. **Database**, 6. **Cache** (each with a "none" option), 7. **Extra services** (optional, add any of the ~90 others: search, queues, AI, mail, monitoring, admin tools), 8. **Workspace tools** (the ~87 tools inside your dev shell: Xdebug, database clients, WP-CLI, see the [Workspace guide](https://laradock.io/docs/services/workspace)), 9. **Project name**, 10. **App path**, then a **review screen** where you can change any answer before anything is saved. ``` ────────────────────────────────────────────────────────────── Step 8 of 10 Workspace tools ────────────────────────────────────────────────────────────── The workspace is your dev shell: the container you run php, composer, artisan, npm and git inside (./laradock workspace). These are the tools baked into it. Debug & testing xdebug pcov phpdbg dusk-deps taint ... type to filter Β· ↑↓ move Β· space toggles on/off Β· enter when done ``` The review screen groups your answers and shows the stack they add up to, before anything is written: ``` ────────────────────────────────────────────────────────────── Review your choices nothing is written yet ────────────────────────────────────────────────────────────── β–Έ Your app 1) Project laravel β–Έ PHP 2) Version 8.4 3) Runtime php-fpm β–Έ Services to run 4) Web server nginx 5) Database mysql 6) Cache redis 7) Extras none β–Έ Dev shell 8) Workspace tools 9 tools (node, yarn, npm-gulp +6 more) β–Έ Naming & location 9) Project name my-app 10) App path ../ ────────────────────────────────────────────────────────────── Starts 5 containers: nginx php-fpm mysql redis workspace ────────────────────────────────────────────────────────────── Enter = apply Β· 1-10 = change that answer Β· q = quit ``` Nothing is written until you confirm. When it finishes, it offers to point your app at the services and to **start your stack right there**, so a first run really can be just `./laradock start`. **Run it again any time you change your mind.** `./laradock setup` is not just a first-run wizard: it pre-fills every answer with the stack you already have, so the review screen shows what you're actually running. Press `7` to add or drop extra services, `5` to switch database, `8` to add a tool like Xdebug, `2` to switch PHP version, and Enter to apply. Anything you don't touch stays exactly as it was. If you already know the name of what you want, `./laradock start ` skips the wizard entirely. What it writes into `.env` (and nothing else): - `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, **unique per project**, so running several Laradock projects on one machine never mixes containers or database files. - `PHP_VERSION`, `APP_CODE_PATH_HOST`, and `LARADOCK_SERVICES` (your default service set for `./laradock start`). - Everything else keeps its shipped default from each service's [`defaults.env`](https://laradock.io/docs/getting-started#how-laradock-configuration-works). ### Pointing your app at the services The most common first-run snag in any Docker setup is your app's own `.env` still saying `DB_HOST=127.0.0.1`. The wizard offers to fix that: it shows you the exact changes first, backs up your file to `.env.bak.laradock`, and tags every line it writes with `# set by laradock`: ``` Point your app's .env at these services? DB_CONNECTION=sqlite β†’ DB_CONNECTION=mysql + DB_HOST=mysql REDIS_HOST=127.0.0.1 β†’ REDIS_HOST=redis Apply (original backed up to .env.bak.laradock)? [Y/n] ``` If you later edit a tagged line yourself, the wizard **never touches it again**, your value wins permanently. Decline the prompt and nothing in your app is ever modified. ## Changing things later - **See what a service lets you change:** `./laradock settings mysql` (every variable with its current value; your overrides highlighted). Bare `./laradock settings` lists everything you've customized. - **Change a setting:** `./laradock set KEY=VALUE` (or edit the line in `.env` yourself; it beats every default). The CLI then offers the restart, or points you at `./laradock rebuild ` for build-time settings, and even warns you when a database password can't apply to existing data. - **Undo a change:** `./laradock unset KEY`, back to the shipped default. - **A port is taken:** the error tells you exactly which variable to change, suggests a free port, and offers to fix it and start again for you. One keypress. - **Add a service:** `./laradock start mailpit` (100+ available; the folder name is the service name). - **See how to connect:** `./laradock info`. - **Something's wrong:** `./laradock doctor`, then `./laradock logs `. ## Advanced: nothing is hidden The CLI is **not** a black box or a new system to learn. It's a small, readable bash script sitting in the repo root that just runs the same Docker commands you could run yourself, and it's optional. Two things are worth knowing once you're comfortable: - **It's a friendly wrapper, not a replacement.** Every command it runs is plain `docker compose` under the hood, and it prints that real command before running it, so you can see (and learn) exactly what's happening. Anything it doesn't recognize is passed straight through: `./laradock ps`, `./laradock config`, `./laradock down` all just work. - **You never lose full control.** The only file it writes is the same `.env` you'd write by hand. The moment you need advanced customization, you can drop down to plain `docker compose` and the raw config files, everything is yours to inspect and edit. That's why, throughout these docs, most tasks show **two ways** to do them: the easy CLI command first, and the manual `docker compose` equivalent right below it. Use whichever you like, they do the exact same thing, and you can mix and switch any time. Here's the full map: every CLI command and the exact `docker compose` it runs underneath (`[services]` is optional, `` is required): | Task | Easy: the CLI | Full control: Docker Compose | |---|---|---| | Set up | `./laradock setup` | `cp .env.example .env`, then edit (the wizard only writes `.env`) | | Start | `./laradock start [services]` | `docker compose up -d [services]` | | Stop | `./laradock stop [services]` | `docker compose stop [services]` | | Restart | `./laradock restart [services]` | `docker compose restart [services]` | | Delete containers | `./laradock remove [services]` | `docker compose rm -sf [services]` | | Rebuild | `./laradock rebuild [services]` | `docker compose build [services]` | | View logs | `./laradock logs [services]` | `docker compose logs --tail=100 [services]` | | What's running | `./laradock info` | `docker compose ps` (plus URLs, ports, passwords) | | Enter a container | `./laradock enter ` | `docker compose exec bash` | | Run one command | `./laradock exec ` | `docker compose exec ` | | Enter the dev shell | `./laradock workspace` | `docker compose exec workspace bash` | | Open a SQL shell | `./laradock db` | `docker compose exec mysql mysql …` (auto-detects MySQL / MariaDB / PostgreSQL) | | Run your tests | `./laradock test` | `docker compose exec -u laradock workspace php artisan test` (auto-detects Artisan / Pest / PHPUnit) | | Change a setting | `./laradock set KEY=VALUE` | Writes the line to your `.env` (no container command; you'd edit `.env` by hand) | | Undo a setting | `./laradock unset KEY` | Removes the line from your `.env` | | See settings | `./laradock settings [service]` | Reads each `defaults.env` + your `.env` (nothing to run) | | Edit a file | `./laradock edit [service]` | Opens `.env` (or a service's `Dockerfile`) in your editor | | Open in browser | `./laradock open [ui]` | Opens the URL, e.g. `http://localhost` (no container command) | | Public preview URL | `./laradock share` | Runs `cloudflared` or `ngrok` against your local port | | Health check | `./laradock doctor` | Runs local checks and suggests fixes | | Build a prod image | `./laradock ship [tag]` | `docker build` a deployable image, see [Deploy to Production](https://laradock.io/docs/production) | | Anything else | `./laradock …` | `docker compose …` (pass-through: `ps`, `config`, `top`, …) | The CLI prints the real `docker compose` line before it runs it, so you can watch (and learn) exactly what each command does. ================================================================ # Community Source: https://laradock.io/docs/community ================================================================ Welcome to the Laradock community. Whether you're stuck on a setup, curious how others run their stack, or want to help shape what's next, you're in the right place. ![Docker Image](https://laradock.io/img/laradock/laradock-abstract-thinner.jpg) ## Where the community lives Gitter's done. Our community of **2,000+ active members** has a new home on **GitHub Discussions**, right next to the code, issues, and docs. That's where to ask questions, share your setups, and help other Laradock users. :::note From Gitter to Discussions For years the community chat ran on Gitter, growing to 2,000+ members. Gitter wound down, so as of 2026 everything moved to GitHub Discussions. ::: ## Explore the ecosystem Laradock inspired **[1.5K+ community projects](https://laradock.io/docs/related-projects)**, GUIs, CLIs, Kubernetes playbooks, framework ports, and monitoring helpers. Chances are someone already built the tool you need. ## Other ways to reach us - Need something directly? **mahmoud@zalt.me** - Security vulnerabilities: see the [Security Policy](https://github.com/laradock/laradock/blob/master/SECURITY.md). - Want to help? See [Contributing](https://laradock.io/docs/contributing) and [Help & Troubleshooting](https://laradock.io/docs/help). ================================================================ # Managing Containers Source: https://laradock.io/docs/containers ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; The core commands you use every day to start, stop, inspect, and rebuild your stack. **Configuring one specific service?** The commands here work on any container, but each service also has its own page with its `.env` flags, ports, and default credentials: Not listed? Browse the [full catalog of 100+ services](https://laradock.io/docs/Intro#supported-services). ## List running containers ```bash ./laradock info ``` Shows what's running, plus the URLs, ports, and passwords to reach each service. ```bash docker compose ps # Or use Docker directly (all containers, not just this project): docker ps ``` ## Enter a container Open a shell inside a running container to run commands in it. ```bash ./laradock enter mysql ``` ```bash docker compose exec mysql bash ``` Swap `mysql` for any container name. To open the MySQL prompt directly instead of a shell: ```bash ./laradock exec mysql mysql -udefault -psecret ``` ```bash docker compose exec mysql mysql -udefault -psecret ``` Type `exit` to leave. :::tip `./laradock enter` always uses the `laradock` user in the `workspace` container, so files it creates are owned by your host user (not root). Need root instead? `./laradock enter workspace --root`, or manually: `docker compose exec --user=laradock workspace bash`. ::: ## Stop containers Stop everything: ```bash ./laradock stop ``` ```bash docker compose stop ``` Stop a single container: ```bash ./laradock stop mysql ``` ```bash docker compose stop mysql ``` ## Delete containers ```bash ./laradock remove ``` ```bash docker compose down ``` Your data on disk is untouched either way, it lives under `DATA_PATH_HOST`, outside the containers (see [Data & Volumes](https://laradock.io/docs/volumes)). `docker compose down` additionally tears down the project's network, rarely something you need to think about for local dev. ## View logs NGINX writes its logs to the `logs/nginx` directory. For any other container, use: ```bash ./laradock logs mysql ``` ```bash docker compose logs mysql ``` Follow the log live with `-f`: ```bash ./laradock logs mysql -f ``` ```bash docker compose logs -f mysql ``` See the [Docker Compose logs options](https://docs.docker.com/compose/reference/logs/) for more. ## Build or rebuild containers After editing any `Dockerfile`, rebuild for the change to take effect: ```bash ./laradock rebuild ``` ```bash docker compose build ``` Rebuild a single container instead of all of them: ```bash ./laradock rebuild mysql ``` ```bash docker compose build mysql ``` Use `--no-cache` to force a full, clean rebuild: ```bash ./laradock rebuild --no-cache mysql ``` ```bash docker compose build --no-cache mysql ``` ## Edit a container's Compose config Everything about a service lives in its folder: its container definition in `/compose.yml` and its settings in `/defaults.env`. For plain value changes (ports, versions, credentials), don't edit files at all, just override the variable in your `.env`. Edit `/compose.yml` only for structural changes. *Change the MySQL database name (in `mysql/compose.yml`):* ```yml environment: MYSQL_DATABASE: laradock ... ``` *Map Redis to a different host port (`1111`), no file editing needed, just add to your `.env`:* ```env REDIS_PORT=1111 ``` ## Edit a Docker image 1. Find the image's `Dockerfile`, for `mysql` it's `mysql/Dockerfile`. 2. Edit it as you like. 3. Rebuild the container: `./laradock rebuild mysql` (or `docker compose build mysql`). For the common cases, toggling a bundled feature, installing a PHP extension, or adding a system package, see [Customizing Images](https://laradock.io/docs/customizing-images). ## Add more services Chances are the service you want already ships with Laradock, browse the [full catalog of 100+ services](https://laradock.io/docs/Intro#supported-services) first. To add a genuinely new one, create a folder for it containing a `compose.yml` with your container definition (plus a `defaults.env` for its settings, if any), then register it in the root `docker-compose.yml` by adding an `include` entry like the existing ones. You'll want to be familiar with the [Docker Compose file syntax](https://docs.docker.com/compose/compose-file/). ================================================================ # Customizing Images Source: https://laradock.io/docs/customizing-images ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Every container is built from a plain, readable `Dockerfile` in that service's folder (`php-fpm/Dockerfile`, `workspace/Dockerfile`, and so on), and you own all of them. So you can change what goes inside any image. There are three levels, from "no file editing" to "edit the Dockerfile"; pick the lowest one that does the job. ## Level 1: toggle a bundled feature from `.env` Most of what you'd want is already in the image, behind an off switch. Each container's `defaults.env` lists its build flags; flip one in your `.env` and rebuild. Nothing about the mechanism is hidden: that flag is passed into the Dockerfile as a **build argument** (`PHP_FPM_INSTALL_GMP` in your `.env` becomes the `INSTALL_GMP` arg in `php-fpm/compose.yml`), and the Dockerfile installs the feature when it's `true`. ```env PHP_FPM_INSTALL_GMP=true ``` ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` ## Level 2: install a PHP extension PHP extensions are just Level-1 flags, one per extension, in `php-fpm/defaults.env`, `workspace/defaults.env`, and `php-worker/defaults.env`. Set the flag in your `.env` and rebuild that container. The [PHP-FPM page](https://laradock.io/docs/services/php-fpm#install-php-extensions) has the full list and the per-extension notes (some need extra settings). ## Level 3: add your own system package For something Laradock has no flag for, edit that service's `Dockerfile` directly. To add a system package to the Workspace, add an `apt-get install` line to `workspace/Dockerfile`: ```dockerfile RUN apt-get update && apt-get install -yqq \ your-package \ && apt-get clean ``` Then rebuild the container so the change is baked in: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` :::tip A `Dockerfile` change only takes effect after a rebuild. If a change seems stuck (a cached layer), force a clean build with `./laradock rebuild --no-cache workspace` (or `docker compose build --no-cache workspace`). ::: ## Run more than one PHP version Changing `PHP_VERSION` switches the version for the whole stack. To run **two versions at the same time** (for example a legacy app on PHP 7.4 next to a new project on PHP 8.3), Laradock ships an opt-in overlay, see [Multiple PHP Versions](https://laradock.io/docs/multiple-php-versions). ## Keep your changes upstream-safe Editing files inside Laradock means your changes live in the Laradock repo, not your app. To keep them under version control while still pulling updates, track Laradock as your own fork, see [Track your own changes](https://laradock.io/docs/maintenance#track-your-own-changes). ================================================================ # Deploy to a Single Server Source: https://laradock.io/docs/deploy-to-a-server ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **one server** (a VPS, EC2 instance, or droplet) without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm), and a ready Compose file runs it. ## 1. Build the image ```bash ./laradock ship # or: ./laradock ship registry/you/app:1.0 --push ``` ## 2. Run it on the server Laradock ships a ready [`compose.yml`](https://github.com/laradock/laradock/blob/master/production/compose.yml). On the server: ```bash cp laradock/production/.env.example laradock/production/.env # fill real values docker compose -f laradock/production/compose.yml up -d ``` Optional worker and scheduler are one flag away: `--profile worker --profile scheduler`. ## Notes - **Managed database.** Point `DB_*` / `REDIS_*` at a managed service; the Compose file deliberately does **not** expose a database port. - **HTTPS.** Put a reverse proxy in front (Caddy or Traefik give you automatic TLS). - **Scaling past one box?** Move to [Kamal](https://laradock.io/docs/deploy-to-kamal) or [Kubernetes](https://laradock.io/docs/deploy-to-kubernetes), same image. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, ECS, Cloud Run, Fly, Render, and more. ================================================================ # Deploy to AWS App Runner Source: https://laradock.io/docs/deploy-to-aws-app-runner ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **AWS App Runner** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm); App Runner runs it on port 8080 with HTTPS and autoscaling built in, no load balancer to configure. ## 1. Build and push to ECR ```bash aws ecr create-repository --repository-name laradock-app ./laradock ship .dkr.ecr..amazonaws.com/laradock-app:latest --push ``` ## 2. Create the service Laradock ships a ready [`aws-app-runner.json`](https://github.com/laradock/laradock/blob/master/production/providers/aws-app-runner.json) (ECR image, `Port: 8080`, health check, auto-deploy). Fill in your image, then: ```bash aws apprunner create-service --cli-input-json file://aws-app-runner.json ``` ## Notes - **Managed database.** Use **RDS**; connect via a VPC connector. - **Secrets** come from App Runner runtime env / Secrets Manager, never the image. - **Auto-deploy.** With `AutoDeploymentsEnabled`, App Runner redeploys when you push a new image tag. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy to AWS ECS / Fargate Source: https://laradock.io/docs/deploy-to-aws-ecs ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **AWS ECS on Fargate** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm, serving `$PORT`); ECS runs it as a task, no servers to manage. ## 1. Build and push to ECR ```bash aws ecr create-repository --repository-name laradock-app ./laradock ship .dkr.ecr..amazonaws.com/laradock-app:latest --push ``` ## 2. Register the task and run it Laradock ships a ready [`aws-ecs-task-definition.json`](https://github.com/laradock/laradock/blob/master/production/providers/aws-ecs-task-definition.json) (Fargate, awsvpc, port 8080, CloudWatch logs, Secrets Manager). Fill in your account, region, and image, then: ```bash aws ecs register-task-definition --cli-input-json file://aws-ecs-task-definition.json aws ecs create-service --cluster my-cluster --service-name laradock-app \ --task-definition laradock-app --desired-count 1 --launch-type FARGATE ``` ## Notes - **Managed database.** Use **RDS**; put the password in **Secrets Manager** and reference it in the task (already wired in the template). - **HTTPS + routing.** Put an **Application Load Balancer** in front, targeting container port 8080. - **Secrets** never go in the image, they come from Secrets Manager / task env at runtime. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, Cloud Run, Fly, Render, and more. ================================================================ # Deploy to Azure Container Apps Source: https://laradock.io/docs/deploy-to-azure-container-apps ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Azure Container Apps** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm) that Container Apps runs on port 8080 with autoscaling. ## 1. Build and push to ACR ```bash az acr create -g -n --sku Basic ./laradock ship .azurecr.io/laradock-app:latest --push ``` ## 2. Create the app Laradock ships a ready [`azure-container-app.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/azure-container-app.yaml) (ingress `targetPort: 8080`, secrets, scale rules). Fill in your image, then: ```bash az containerapp create -g -n laradock-app \ --environment --yaml laradock/production/providers/azure-container-app.yaml ``` ## Notes - **Managed database.** Use **Azure Database for MySQL/PostgreSQL** and **Azure Cache for Redis**. - **Secrets** map to Container Apps secrets (or Key Vault), never bake them into the image. - **Scaling.** Tune `minReplicas` / `maxReplicas` (KEDA-based) in the YAML. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy to DigitalOcean App Platform Source: https://laradock.io/docs/deploy-to-digitalocean ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **DigitalOcean App Platform** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm) that App Platform runs on port 8080. ## 1. Build and push the image Push to the DigitalOcean Container Registry (DOCR), Docker Hub, or GHCR: ```bash ./laradock ship registry.digitalocean.com/you/laradock-app:latest --push ``` ## 2. Create the app Laradock ships a ready [`digitalocean-app.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/digitalocean-app.yaml) (App spec, `http_port: 8080`, health check). Fill in your image, then: ```bash doctl apps create --spec laradock/production/providers/digitalocean-app.yaml ``` ## Notes - **Managed database.** Attach a **DigitalOcean Managed Database** (Postgres/MySQL) and **Managed Redis**. - **Secrets** use `type: SECRET` env vars, never bake them into the image. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy to Fly.io Source: https://laradock.io/docs/deploy-to-fly-io ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Fly.io** without changing your stack. Fly builds the self-contained image (nginx + php-fpm) straight from the production Dockerfile and runs it close to your users. ## 1. Add the config Copy the ready [`fly.toml`](https://github.com/laradock/laradock/blob/master/production/providers/fly.toml) to your project root. It points Fly at `laradock/production/Dockerfile` and routes HTTPS to port 8080. ## 2. Launch and deploy ```bash fly launch --no-deploy # first time, creates the app fly secrets set APP_KEY=… DB_PASSWORD=… fly deploy ``` ## Notes - **Managed database.** Use **Fly Postgres** or a managed provider; **Upstash Redis** for cache/queue. - **Secrets** live in `fly secrets`, never in the image. - **Regions.** Add more with `fly regions add`, the same image runs everywhere. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Render, and more. ================================================================ # Deploy to Google Cloud Run Source: https://laradock.io/docs/deploy-to-google-cloud-run ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Google Cloud Run** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm) that listens on the `$PORT` Cloud Run injects, so it just works, and scales to zero when idle. ## 1. Build and push to Artifact Registry ```bash ./laradock ship -docker.pkg.dev///laradock-app:latest --push ``` ## 2. Deploy the service Laradock ships a ready [`google-cloud-run.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/google-cloud-run.yaml) (Knative Service, containerPort 8080, Secret Manager env). Fill in your image, then: ```bash gcloud run services replace laradock/production/providers/google-cloud-run.yaml --region=us-central1 ``` Or the one-liner: `gcloud run deploy laradock-app --image= --port=8080 --region=us-central1`. ## Notes - **Managed database.** Use **Cloud SQL** (add the connector) and **Memorystore** for Redis. - **Secrets.** Reference **Secret Manager** entries (already wired in the template). - **Scale to zero.** Cloud Run stops instances when idle; set `min-instances` if you need one always warm. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Fly, Render, and more. ================================================================ # Deploy to Heroku Source: https://laradock.io/docs/deploy-to-heroku ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Heroku** (container stack) without changing your stack. The self-contained image (nginx + php-fpm) listens on the `$PORT` Heroku assigns. ## 1. Add the config Copy the ready [`heroku.yml`](https://github.com/laradock/laradock/blob/master/production/providers/heroku.yml) to your project root. It builds the web process from `laradock/production/Dockerfile`. ## 2. Deploy ```bash heroku create && heroku stack:set container heroku config:set APP_ENV=production DB_HOST=… DB_PASSWORD=… git push heroku main ``` ## Notes - **Managed database.** Add **Heroku Postgres** and **Heroku Data for Redis**. - **Config vars** are injected as env, never bake secrets into the image. - **Worker.** Uncomment the `worker` process in `heroku.yml`, then `heroku ps:scale worker=1`. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy with Kamal (your own servers) Source: https://laradock.io/docs/deploy-to-kamal ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **your own servers** (a VPS, bare metal, anywhere) with [Kamal](https://kamal-deploy.org), no Kubernetes needed. Kamal builds the self-contained image (nginx + php-fpm) and rolls it out with zero downtime, its proxy handles TLS. ## 1. Add the config Copy the ready [`kamal-deploy.yml`](https://github.com/laradock/laradock/blob/master/production/providers/kamal-deploy.yml) to `config/deploy.yml`. It builds from `laradock/production/Dockerfile`, serves port 8080, and terminates TLS at the proxy. ## 2. Deploy ```bash # put secrets in .kamal/secrets, then: kamal setup # first time kamal deploy # every release ``` ## Notes - **Managed database.** Point `DB_*` at a managed provider, or run a database as a Kamal accessory. - **Secrets** live in `.kamal/secrets`, never in the image. - **Zero downtime.** Kamal boots the new container, health-checks it, then swaps traffic. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy to Kubernetes Source: https://laradock.io/docs/deploy-to-kubernetes ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Kubernetes** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm, serving `$PORT`); your cluster just runs it, whether that's your own, **EKS**, **GKE**, **AKS**, or **DOKS**. ## 1. Build and push the image ```bash ./laradock ship registry.example.com/you/app:1.0 --push ``` ## 2. Apply the manifests Laradock ships a ready [`kubernetes.yaml`](https://github.com/laradock/laradock/blob/master/production/kubernetes.yaml): a deployment (resource limits + probes), a service, a TLS-ready ingress (cert-manager), an uploads PVC, plus optional worker, scheduler CronJob, and migrate Job. ```bash kubectl create secret generic app-env --from-env-file=laradock/production/.env # set image: to your pushed image in kubernetes.yaml, then: kubectl apply -f laradock/production/kubernetes.yaml ``` ## Notes - **Managed database.** Point `DB_*` / `REDIS_*` at RDS, Cloud SQL, or your provider's managed service, never a pod. - **TLS.** Install [cert-manager](https://cert-manager.io) and set your issuer in the ingress annotations. - **Uploads.** Multiple replicas need `ReadWriteMany` storage or S3 (see the PVC note in the manifest). Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, ECS, Cloud Run, Fly, Render, and more. ================================================================ # Deploy to Railway Source: https://laradock.io/docs/deploy-to-railway ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Railway** without changing your stack. Railway builds the self-contained image (nginx + php-fpm) from the production Dockerfile and injects `$PORT`, which the image honors. ## 1. Add the config Copy the ready [`railway.json`](https://github.com/laradock/laradock/blob/master/production/providers/railway.json) to your project root. It tells Railway to build from `laradock/production/Dockerfile` and health-check `/`. ## 2. Deploy ```bash railway init railway up ``` Or connect the repo in the Railway dashboard, it deploys on every push. Set env vars (`DB_HOST`, `DB_PASSWORD`, `APP_KEY`) in the service settings. ## Notes - **Managed database.** Add **Railway Postgres** and **Railway Redis** as plugins, or use a managed provider. - **Secrets** are service variables, never in the image. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Deploy to Render Source: https://laradock.io/docs/deploy-to-render ================================================================ Built your app with [Laradock](https://laradock.io/docs/Intro)? Ship it to **Render** without changing your stack. `./laradock ship` builds one self-contained image (nginx + php-fpm) that listens on the `$PORT` Render injects. ## 1. Add the Blueprint Copy the ready [`render.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/render.yaml) to your project root. It defines a web service that runs your image (or builds from the production Dockerfile). ## 2. Deploy In the Render dashboard: **New > Blueprint**, point it at your repo, and set secret env vars (`DB_PASSWORD`, `APP_KEY`). Render builds and deploys on every push. ## Notes - **Managed database.** Use **Render Postgres** and **Render Redis**, or any managed provider. - **Secrets** are set in the dashboard (`sync: false` in the Blueprint), never in git. - **Health checks** hit `/` by default; point them at a real health route if you have one. Deploying elsewhere? The [full deploy guide](https://laradock.io/docs/production) covers every target, Kubernetes, ECS, Cloud Run, Fly, and more. ================================================================ # Environment & Platform Source: https://laradock.io/docs/environment ================================================================ Workspace access, host-specific tuning, and scheduling. ## Access the workspace over SSH Reach the Workspace at `localhost:2222` by setting `WORKSPACE_INSTALL_WORKSPACE_SSH=true` in your `.env` and rebuilding the workspace. To change the forwarded port, add it to your `.env` (the default lives in `workspace/defaults.env`): ```env WORKSPACE_SSH_PORT=2222 ``` Then connect: ```bash ssh -o PasswordAuthentication=no \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ -p 2222 \ -i workspace/insecure_id_rsa \ laradock@localhost ``` > Replace `laradock@localhost` with `root@localhost` to log in as root. ## Change the timezone Set `WORKSPACE_TIMEZONE` in your `.env` to any value from the [TZ database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), then rebuild. For example, New York: ```env WORKSPACE_TIMEZONE=America/New_York ``` We also recommend [setting the timezone in Laravel](http://www.camroncade.com/managing-timezones-with-laravel/). ## Add locales to PHP-FPM #### Add locales 1. In `.env`, set `PHP_FPM_INSTALL_ADDITIONAL_LOCALES` to `true`. 2. Add the locale codes to `PHP_FPM_ADDITIONAL_LOCALES`. 3. Rebuild: `./laradock rebuild php-fpm` (or `docker compose build php-fpm`). 4. Check them: `./laradock enter php-fpm` then `locale -a` (or `docker compose exec php-fpm locale -a`). **Change the default locale** (default is `POSIX`): 1. In `.env`, set `PHP_FPM_DEFAULT_LOCALE` to your locale, for example `en_US.UTF8`. 2. Rebuild: `./laradock rebuild php-fpm` (or `docker compose build php-fpm`). 3. Check it: `./laradock enter php-fpm` then `locale` (or `docker compose exec php-fpm locale`). ## Add cron jobs Add your cron jobs to `workspace/crontab/laradock`, after the `php artisan` line: ``` * * * * * laradock /usr/bin/php /var/www/artisan schedule:run >> /dev/null 2>&1 # Custom cron * * * * * root echo "Every Minute" > /var/log/cron.log 2>&1 ``` :::note [Change the timezone](#change-the-timezone) if you don't want UTC. On Windows, make sure this file uses LF line endings, or the cron jobs silently fail. ::: ## Improve speed on macOS Sharing your code from macOS into containers is slower than on Linux because every file read crosses the host/VM boundary. Recent Docker Desktop fixes most of this on its own, so the steps below go from "do this first" to "only if you still need it." **1. Enable VirtioFS (fixes most cases).** In Docker Desktop, open **Settings β†’ General β†’ Choose file sharing implementation for your containers** and pick **VirtioFS**, then **Apply & Restart**. It is the default on recent Docker Desktop and is dramatically faster than the older osxfs / gRPC FUSE backends. For most projects this alone is enough. **2. Tune the mount flag.** Laradock mounts your code using the `APP_CODE_CONTAINER_FLAG` value in your `.env` (default `:cached`). Keep `:cached` for most apps. If your app writes heavily to the mounted volume, `:delegated` can be faster, at the cost of the container's view lagging the host by a moment: ```dotenv APP_CODE_CONTAINER_FLAG=:delegated ``` **3. Keep large directories out of the bind mount.** The real cost is bind-mounting tens of thousands of files. Directories your host doesn't need to read, such as `vendor/` and `node_modules/`, are best kept in a Docker volume instead of the host mount so they never cross the file-sharing boundary. **4. Still too slow? Use Mutagen.** For very large codebases, [Mutagen](https://mutagen.io) syncs your files into a native container volume in the background, giving near-Linux speed. It is the maintained successor to the old `docker-sync` approach. ================================================================ # How-To Guides Source: https://laradock.io/docs/how-to-guides ================================================================ import DocCardList from '@theme/DocCardList'; Once Laradock is running, these are the things you'll actually reach for. Each guide is short and task-focused: one problem, the commands to solve it, and the reasoning behind them. ## Start here If you're new, do these in order: bring up your [containers](https://laradock.io/docs/containers), learn how [volumes](https://laradock.io/docs/volumes) persist your data, and skim [environment](https://laradock.io/docs/environment) so you know where settings live. That's enough to be productive. ## Then reach for the rest as needed The other guides answer specific questions as they come up, running [multiple projects](https://laradock.io/docs/multiple-projects) or [multiple PHP versions](https://laradock.io/docs/multiple-php-versions) side by side, [customizing images](https://laradock.io/docs/customizing-images), wiring up [Xdebug in your IDE](https://laradock.io/docs/xdebug-ide), or [networking](https://laradock.io/docs/networking) between containers. You don't need to read them front to back; jump to the one that matches what you're stuck on. ## All guides ================================================================ # Laradock vs docker-magento and Warden Source: https://laradock.io/docs/laradock-vs-docker-magento ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What are docker-magento and Warden? Magento 2 is heavy: it needs specific PHP extensions, a search engine (OpenSearch/Elasticsearch), Redis, RabbitMQ, and often Varnish. Two community setups are tuned for exactly that: - [**Mark Shust's docker-magento**](https://github.com/markshust/docker-magento) is the most popular Magento-specific Docker environment: a Compose stack plus `bin/` helper scripts pre-configured with the extensions, search, cache, and SSL a Magento 2 store expects. - [**Warden**](https://warden.dev/) is a CLI that runs shared services (Traefik, Portainer, dnsmasq, an SSL CA) once on your machine and layers per-project environments on top, popular in Magento agencies juggling many stores. This page compares them with Laradock, which serves the same Magento stack but as one framework-agnostic environment rather than a Magento-only tool. *docker-magento and Warden are Magento specialists, pre-tuned and excellent at that one job. Laradock is the generalist that also runs Magento, plus every other PHP project, with the same 100+ services and a path to production. This page sets Magento up on Laradock.* **TL;DR:** pick [docker-magento](https://github.com/markshust/docker-magento) or [Warden](https://warden.dev/) if Magento is essentially all you do and you want a stack pre-tuned for it. Pick Laradock when Magento is one of several project types you work on, you want a single environment across all of them, or you want the same containers to reach production. ## Setting up with docker-magento ```bash curl -s https://raw.githubusercontent.com/markshust/docker-magento/master/lib/onelinesetup | bash -s -- magento.test 2.4.7 ``` That one-liner provisions a full Magento-tuned stack (PHP with the right extensions, OpenSearch, Redis, RabbitMQ, Varnish, MailHog, SSL) and installs Magento. Day to day you use its `bin/` helpers: `bin/magento`, `bin/composer`, `bin/cli`. It is superb for Magento and only Magento; the stack and scripts assume a Magento project. ## The same thing with Laradock ```bash cd my-store git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis opensearch rabbitmq workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis opensearch rabbitmq workspace docker compose exec workspace bash ``` Everything Magento needs is a service you switch on: OpenSearch/Elasticsearch, Redis, RabbitMQ, and Varnish are all in the catalog, and the `workspace` container runs Composer and `bin/magento`. The difference is scope: the exact same Laradock also runs your Laravel API, a WordPress marketing site, or a Symfony service, no second tool. Full walkthrough: **[Run Magento on Docker](https://laradock.io/docs/magento-on-docker)**. ## Side by side | | **docker-magento** | **Warden** | **Laradock** | |---|---|---|---| | Focus | Magento only | Magento / PHP (agency multi-project) | Any PHP project | | Install | Clone + `bin/` scripts | The `warden` binary | Nothing (git clone) | | Commands | `bin/magento`, `bin/composer` | `warden` CLI | Plain `docker compose` (+ optional `./laradock`) | | Magento tuning | βœ… pre-configured | βœ… pre-configured | You start the services (OpenSearch, Redis, RabbitMQ, Varnish) | | Shared services model | Per-project | βœ… shared (Traefik/dnsmasq) | Per-project (or share one Laradock) | | Runs non-Magento projects | ❌ | Limited | βœ… 100+ services, any framework | | Auto HTTPS + `.test` domains | βœ… | βœ… | Via Caddy/Traefik service | | Production path | Dev-focused | Dev-focused | `./laradock ship` β†’ server / Kubernetes / cloud | ## Choose docker-magento or Warden if... - Magento 2 is essentially all you build, and you want a stack pre-tuned for it out of the box. - You value Magento-specific helper commands and defaults over a general-purpose environment. - (Warden) You run many Magento stores and want shared Traefik/dnsmasq/SSL handled once. ## Choose Laradock if... - Magento is one of several project types you touch, and you want **one** environment for all of them. - You prefer plain `docker compose` and readable files over a Magento-specific CLI vocabulary. - You want the broadest service catalog (100+), including things a Magento stack does not ship. - You want the same containers to reach production with `./laradock ship`. ## Frequently Asked Questions ### Can Laradock run Magento 2? Yes. Start `opensearch` (or `elasticsearch`), `redis`, `rabbitmq`, and optionally `varnish` alongside `nginx`, `mysql`, and `workspace`, then install Magento with Composer inside the workspace. See **[Run Magento on Docker](https://laradock.io/docs/magento-on-docker)**. ### Is docker-magento better than Laradock for Magento? For a pure-Magento shop, docker-magento arrives pre-tuned and is hard to beat on convenience. Laradock wins when Magento is not your only project type, when you want one environment across frameworks, or when you want a direct path to production with the same containers. ### Does Warden replace Laradock? They overlap for Magento agencies. Warden optimizes for many similar Magento stores with shared services; Laradock optimizes for breadth (any PHP project, 100+ services) and transparency (plain Docker files you own). See the full landscape: **[Laradock vs DDEV](https://laradock.io/docs/laradock-vs-ddev)** and **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Run Magento on Docker](https://laradock.io/docs/magento-on-docker)** walks through it end to end. ================================================================ # Laradock vs Drupal Docker (DDEV and the official image) Source: https://laradock.io/docs/laradock-vs-drupal-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## How Drupal is usually run in Docker Drupal has no single official Docker tool, but the community has clear defaults: - [**DDEV**](https://ddev.com/) is the de-facto standard the Drupal community recommends: install one binary, run `ddev start`, and a Drupal-ready environment appears with automatic HTTPS and per-project domains. (Lando is a close cousin, popular for the same reason.) - The [**official `drupal` Docker image**](https://hub.docker.com/_/drupal) is a bare runtime you pair with a database in a `docker-compose.yml` you write yourself. This page compares those with Laradock. For the general, tool-level DDEV comparison see **[Laradock vs DDEV](https://laradock.io/docs/laradock-vs-ddev)**; here the focus is Drupal specifically. *DDEV/Lando generate and hide the Docker machinery behind a CLI; the official image is a building block you wire yourself; Laradock hands you the machinery pre-wired and readable, for Drupal and every other PHP project. This page sets Drupal up on Laradock.* **TL;DR:** pick [DDEV](https://ddev.com/) if you run many Drupal sites and never want to see a Dockerfile. Wire the [official image](https://hub.docker.com/_/drupal) yourself if your needs are tiny. Pick Laradock if you want full control over readable Docker files, services beyond DDEV's add-ons, one environment across frameworks, or a direct path to production. ## Setting up Drupal with DDEV ```bash mkdir my-drupal && cd my-drupal ddev config --project-type=drupal --docroot=web ddev start ddev composer create drupal/recommended-project ddev drush site:install -y ddev launch ``` Live at `https://my-drupal.ddev.site` with trusted HTTPS. The Docker files live in `.ddev/`, generated and regenerated on every start, so they are DDEV's to manage, not yours to edit directly. ## The same thing with Laradock ```bash cd my-drupal git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx postgres redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx postgres redis workspace docker compose exec workspace bash ``` Inside the workspace, `composer create-project drupal/recommended-project .` and `drush site:install` just work (the workspace ships Composer, Drush, and Drupal Console). Every file involved (`nginx/compose.yml`, `php-fpm/Dockerfile`, ...) is readable and yours to edit. Full walkthrough: **[Run Drupal on Docker](https://laradock.io/docs/drupal-on-docker)**. ## Side by side | | **DDEV** | **Official image** | **Laradock** | |---|---|---|---| | Install | `ddev` binary | Nothing (write compose) | Nothing (git clone) | | Docker files | Generated & hidden in `.ddev/` | Yours (you wrote them) | Plain files you own and edit | | Commands | `ddev *` vocabulary | Plain `docker compose` | Plain `docker compose` (+ optional `./laradock`) | | HTTPS + `.site`/`.test` domains | βœ… automatic | Manual | Via Caddy/Traefik service | | Drush / Drupal Console | βœ… | Add a service | βœ… in `workspace` | | Services | ~50 curated add-ons | Only what you wire | 100+ shipped | | Runs non-Drupal projects | βœ… (CMS-focused presets) | You'd rewrite the compose | βœ… any PHP project | | Skills you build | DDEV-specific | Transferable Docker | Transferable Docker | | Production path | Dev-focused | Roll your own | `./laradock ship` β†’ server / Kubernetes / cloud | ## Choose DDEV (or Lando) if... - You run many Drupal sites and want identical, isolated environments with zero Docker exposure. - Automatic HTTPS and per-project domains matter more than seeing how they work. ## Choose the official image if... - Your needs are minimal (Drupal + one database) and you like owning a short compose file. ## Choose Laradock if... - You want full control: every Dockerfile and config readable and yours to change. - Your stack goes beyond DDEV's add-ons (message brokers, search clusters, local LLMs, monitoring). - You work across frameworks and want one environment for Drupal, Laravel, WordPress, and the rest. - You want the same containers to reach production with `./laradock ship`. ## Frequently Asked Questions ### What is the recommended way to run Drupal in Docker? The Drupal community most often points to DDEV. It is excellent if you want zero Docker exposure; Laradock is the alternative when you want transparent, editable Docker files, a larger service catalog, and one environment across multiple frameworks. ### Can Laradock run Drupal with PostgreSQL? Yes. Start `postgres` instead of `mysql` (`./laradock start nginx postgres redis workspace`) and point Drupal's settings at host `postgres`. See **[Run Drupal on Docker](https://laradock.io/docs/drupal-on-docker)**. ### How is this different from the general DDEV comparison? This page focuses on Drupal specifically. For the broader, tool-level breakdown of DDEV vs Laradock across any project, see **[Laradock vs DDEV](https://laradock.io/docs/laradock-vs-ddev)**. See the full landscape: **[Laradock vs DDEV](https://laradock.io/docs/laradock-vs-ddev)** and **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Run Drupal on Docker](https://laradock.io/docs/drupal-on-docker)** takes about five minutes. ================================================================ # Laradock vs Laragon Source: https://laradock.io/docs/laradock-vs-laragon ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laragon? [Laragon](https://laragon.org/) is a free, portable, Windows-native local development environment. It installs Apache or Nginx, PHP, MySQL/MariaDB, and more directly on Windows, automatically creates a virtual host and a pretty `.test` domain for every project you drop into its `www` folder (no manual hosts-file editing), and adds one-click "Quick App" installers for WordPress, Laravel, Symfony, and other stacks. It is widely considered the fastest and most polished of the classic Windows PHP bundles (XAMPP, WAMP, Laragon). This page compares that Windows-native approach to Laradock's containerized one. *Laragon is the best-in-class version of the "install everything on Windows" approach: fast, auto-configured, genuinely pleasant to use. Laradock is a different category entirely: instead of installing software on your OS, it runs the same stack in disposable, cross-platform Docker containers.* **TL;DR:** pick [Laragon](https://laragon.org/) if you are on Windows and want the fastest, most polished native one-click setup. Pick Laradock if you need cross-platform consistency, more than a handful of services, or an environment that resembles a Linux production server. ## Setting up with Laragon 1. Download and run the Laragon installer (or the portable ZIP, no installer needed). 2. Open Laragon, click **Menu β†’ Quick app β†’ Laravel** (or WordPress, Symfony, and others), give it a name. 3. Click **Start All**; your project appears instantly at `http://my-app.test`, virtual host and pretty URL handled automatically. Adding a plain project: drop its folder into `C:\laragon\www`, click **Reload**, and it gets its own `.test` URL. PHP versions, MySQL/MariaDB versions, and Node are swappable from the **Menu β†’ PHP / MySQL** version pickers, which download the version if it is missing. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Your site is served at `http://localhost`. The trade: Laragon's one-click app installers become explicit `./laradock start ` commands, and virtual hosts are configured through nginx site files instead of being fully automatic, in exchange for the same setup working identically on Linux and macOS, plus 100+ services beyond Laragon's built-in set. ## Side by side | | **Laragon** | **Laradock** | |---|---|---| | Platform | Windows only (portable or installed) | Linux, macOS, Windows | | Runs as | Native Apache/Nginx, PHP, MySQL on Windows | Docker containers | | Setup | Download, run, click "Start All" | `git clone` + `docker compose up` | | Virtual hosts | Fully automatic, no hosts-file editing | Manual nginx site config (or automatic with Traefik/Caddy) | | One-click app installs | Quick App menu (WordPress, Laravel, ...) | `docker compose up -d {service}`, 100+ options | | PHP/DB version switching | GUI version picker, auto-downloads | `.env` variable + rebuild | | Isolation between projects | Shared native services across all projects | Full (containers per project) | | Production parity | None (native Windows) | High (Linux containers) | | Price | Free (Laragon Pro paid tier for extras) | Free, MIT | ## Choose Laragon if... - You are on Windows and want the fastest, most beginner-friendly native setup available. - You like a GUI with one-click app installers and zero hosts-file fiddling. - Your stack fits comfortably inside Laragon's built-in service list. ## Choose Laradock if... - You need the same setup to also work on Linux or macOS, for you or your team. - You want your local environment to resemble a real Linux production server. - You need services beyond Laragon's built-in set (queues, search engines, local LLMs, monitoring), each just one `up` command away. ## Already on Laragon? Migrating takes minutes 1. **Export your database** via Laragon's bundled HeidiSQL or phpMyAdmin: right-click your database β†’ Export β†’ SQL file. 2. **Stop Laragon:** click **Stop All** in the Laragon window so ports 80/3306 free up. 3. **Add Laradock** next to your code (inside WSL or Git Bash, since Laradock's setup commands are Unix-shell based): `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `docker compose up -d nginx mysql redis workspace` 5. **Import the database:** `docker compose exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's config:** database host becomes `mysql` (not `localhost`), user `default`, password `secret` (see `mysql/defaults.env`). 7. Your site now answers at `http://localhost` instead of `my-app.test` (wire an nginx site config if you want a custom domain back). ## Frequently Asked Questions ### Is Laragon free? Yes, Laragon's core is free. Laragon Pro is an optional paid tier that adds extra tools and remote/cloud isolation features. ### Does Laragon work on macOS or Linux? No, Laragon is Windows-only. For a cross-platform alternative with the same one-download simplicity, Laradock runs identically on Windows, macOS, and Linux via Docker. ### Does Laragon use Docker? No, Laragon installs Apache/Nginx, PHP, and MySQL/MariaDB directly on Windows as native services; it does not use containers. That is the core difference this page compares. ### Can I run multiple PHP versions in Laragon? Yes, Laragon's PHP version picker can download and switch between multiple PHP versions, but only one is active globally at a time across all projects, unlike Laradock's per-project container isolation. ### How do I move a Laragon project to Docker? Export your database through Laragon's built-in HeidiSQL or phpMyAdmin, then follow the [migration steps](#already-on-laragon-migrating-takes-minutes) above; it takes about 10 minutes. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Local WP Source: https://laradock.io/docs/laradock-vs-local-wp ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Local WP? [Local WP](https://localwp.com/) (formerly Local by Flywheel, now from WP Engine) is a free desktop application, for macOS, Windows, and Linux, built specifically for WordPress local development. You click "Create a new site," and within about two minutes you have a fully working WordPress install with SSL, WP-CLI, and one-click access to phpMyAdmin, Mailhog, and other add-ons, all through a graphical interface, no command line required. It is the most widely used WordPress-specific local tool, and integrates tightly with WP Engine/Flywheel hosting for pushing and pulling sites. This page compares that GUI-first, WordPress-only tool to Laradock's framework-agnostic, file-based approach. *Local WP is purpose-built for one thing and does it extremely well: WordPress, through a polished GUI, with zero configuration. Laradock is purpose-built for everything: any PHP project, through plain files and Docker Compose, with more setup but no ceiling on what it can run.* **TL;DR:** pick [Local WP](https://localwp.com/) if you only build WordPress sites and want the smoothest possible GUI experience, especially if you host on WP Engine or Flywheel. Pick Laradock if you work across multiple frameworks, prefer file-based configuration over a GUI, or need services beyond WordPress's usual stack. ## Setting up a WordPress site with Local WP 1. Download and install the Local WP app. 2. Click **Create a new site**, name it, choose PHP/MySQL/web-server versions (or accept the defaults), and click through the wizard. 3. Local WP builds the environment and opens your new WordPress install, admin credentials included, at a local `.local` domain. Sharing or deploying: right-click the site for **Export** (a zip with `wp-content` plus a database dump) to hand to a teammate, or use **Live Link** / WP Engine's **Local Connect** to push straight to a WP Engine or Flywheel hosting account. ## The same thing with Laradock ```bash cd my-site git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start apache2 mysql phpmyadmin workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d apache2 mysql phpmyadmin workspace docker compose exec workspace bash ``` Inside the workspace: wp-cli, composer, php, all live here. WordPress itself is not bundled, you download it into your project folder (or install via `wp core download` inside the workspace) the same way you would on any host. In exchange, you get a stack that is not locked to WordPress: the identical `./laradock start ` command starts Redis, Elasticsearch, a queue, or any of Laradock's 100+ other services, and the whole setup is plain text files instead of app state. ## Side by side | | **Local WP** | **Laradock** | |---|---|---| | Interface | Desktop GUI app | Command line, plain files | | Scope | WordPress only | Any PHP project | | Setup | Click "Create a new site" | `git clone` + `docker compose up` | | WordPress install | Bundled, one click | You install WordPress yourself (standard `wp-cli`/download) | | Site config | Stored in the app | Plain `.env` + compose files | | Push to production | Live Link / Local Connect (WP Engine, Flywheel) | Any host; you own the deploy pipeline | | Extra services | Curated add-ons (Mailhog, phpMyAdmin, ...) | 100+ services, one command each | | Non-WordPress projects | Not supported | Fully supported | | Price | Free (WP Migrate Pro paid add-on for advanced push/pull) | Free, MIT | ## Choose Local WP if... - You build WordPress sites exclusively and want the smoothest, most GUI-driven workflow available. - You host on WP Engine or Flywheel and want native one-click deploys. - You would rather click through a wizard than edit configuration files. ## Choose Laradock if... - You work across multiple frameworks or CMSs, not just WordPress. - You prefer plain, version-controllable config files over app-managed state. - You need services outside WordPress's usual stack (queues, search clusters, local LLMs) or a non-WP-Engine hosting target. ## Already on Local WP? Migrating takes minutes 1. **Export your site** in Local WP: right-click the site β†’ **Export site**; you get a zip with `wp-content` and a database dump. 2. **Stop the site in Local WP** (or quit the app) so its ports free up. 3. **Add Laradock** next to a new project folder: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start apache2 mysql phpmyadmin workspace` (or `docker compose up -d apache2 mysql phpmyadmin workspace`) 5. **Unzip the export**, copy `wp-content` into your project's WordPress install, and import the database dump via phpMyAdmin (`localhost:8081`) or `./laradock exec -T mysql mysql -uroot -proot default < dump.sql`. 6. **Update `wp-config.php`:** set `DB_HOST` to `mysql` (not `localhost`), and the credentials from `mysql/defaults.env` (or your `.env` overrides). 7. Your site now answers at `http://localhost` instead of Local WP's `.local` domain. ## Frequently Asked Questions ### Is Local WP free? Yes, Local WP is free. WP Migrate Pro, used for advanced push/pull syncing with a live site, is a separate paid add-on. ### Does Local WP work with frameworks other than WordPress? No, Local WP is purpose-built exclusively for WordPress. For other PHP frameworks or a mixed-stack workflow, you need a framework-agnostic tool like Laradock. ### Does Local WP use Docker? Local WP's newer default mode ("Lightning") uses lightweight native services for speed, with an optional container-based mode for older sites; either way, it is managed entirely through the app rather than files you edit directly, unlike Laradock's plain Docker Compose files. ### Can I deploy directly from Local WP to production? Yes, if you host on WP Engine or Flywheel: Local WP's Live Link and Local Connect features push a local site straight to those hosting platforms. For other hosts, you export and deploy manually. ### How do I move a Local WP site to Docker? Export the site from Local WP (zip with `wp-content` and a database dump), then follow the [migration steps](#already-on-local-wp-migrating-takes-minutes) above; expect about 10-15 minutes depending on site size. See the full landscape, including DDEV, Sail, Herd and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs Symfony Docker Source: https://laradock.io/docs/laradock-vs-symfony-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Symfony Docker? [Symfony Docker](https://github.com/dunglas/symfony-docker) is a project template by KΓ©vin Dunglas (a Symfony core member and the author of FrankenPHP). It ships a `Dockerfile` and `compose.yaml` built around [FrankenPHP](https://frankenphp.dev/), giving a new Symfony app a modern, production-capable runtime with HTTP/2, HTTPS, and a built-in worker mode. Separately, the [Symfony CLI](https://symfony.com/download) provides a fast local web server (`symfony server:start`) that runs on your host PHP and can read environment variables from Docker services. This page compares both with Laradock: where Symfony Docker is a single, excellent, Symfony-shaped template, Laradock is a framework-agnostic catalog of 100+ pre-wired services. *Symfony Docker is a lean, FrankenPHP-based template for one Symfony app, and it is genuinely good. Laradock is the broad, pre-wired environment: 100+ services, any PHP project, and a path to production. This page sets Symfony up on both.* **TL;DR:** pick [Symfony Docker](https://github.com/dunglas/symfony-docker) for a single modern Symfony app when its FrankenPHP-based stack fits, it is clean and official-adjacent. Pick Laradock when you need services it does not include, you work across multiple frameworks or projects, or you want a legacy PHP version. (Laradock also ships FrankenPHP as a service, so you keep that option either way.) ## Setting up with Symfony Docker ```bash git clone https://github.com/dunglas/symfony-docker.git my-app cd my-app docker compose build --no-cache docker compose up -d ``` Your app runs on FrankenPHP at `https://localhost` with a trusted local certificate. Add a database via the template's documented Compose overrides, and use `docker compose exec php ...` for Composer and the Symfony console. It is tuned for one Symfony application; a second database, a search cluster, a message broker, or a queue worker are additions you make and maintain in the compose file. ## Setting up with the Symfony CLI ```bash symfony new my-app cd my-app symfony server:start ``` Fast and lightweight, but it runs on **your host's** PHP (not Docker), so PHP versions and extensions are your machine's, and any database/Redis/search service is something you install or run separately. ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Inside the workspace, `composer create-project symfony/skeleton .` (or `symfony console ...`) just works. Want FrankenPHP instead of NGINX + PHP-FPM? It is a Laradock service too: `./laradock start frankenphp`. Need Messenger backed by RabbitMQ, or Meilisearch/Typesense for search? Each is one word. Full walkthrough: **[Run Symfony on Docker](https://laradock.io/docs/symfony-on-docker)**. ## Side by side | | **Symfony Docker** | **Symfony CLI** | **Laradock** | |---|---|---|---| | What it is | FrankenPHP-based project template | Native local web server | Pre-wired Docker environment | | Runtime | FrankenPHP (in Docker) | Your host PHP | PHP-FPM + NGINX/Apache/Caddy, or FrankenPHP/RoadRunner | | Services included | PHP + you add the rest | None (host) | 100+ (databases, caches, queues, search, mail, monitoring) | | Frameworks | Symfony-shaped | Symfony | Any PHP project | | PHP versions | Recent (image-based) | Whatever is on your host | 5.6 - 8.5 | | HTTPS | βœ… automatic (FrankenPHP) | βœ… (`symfony server:ca:install`) | Via Caddy/Traefik/certbot services | | Adding a service later | Edit `compose.yaml` yourself | Install/run it separately | `docker compose up -d {service}` | | Production path | βœ… FrankenPHP image | ❌ dev server | `./laradock ship` β†’ server / Kubernetes / cloud | ## Choose Symfony Docker if... - You are building a single Symfony app and its FrankenPHP-based stack is what you want. - You value a small, Symfony-official-adjacent template maintained by a core contributor. - Your service needs are modest and you are comfortable extending the compose file. ## Choose the Symfony CLI if... - You want the fastest possible local loop and are happy managing PHP and services on your host. ## Choose Laradock if... - You need services beyond the template: multiple databases, RabbitMQ/Kafka, Elasticsearch/Meilisearch, monitoring, local LLMs, each one `up` command away. - You work on more than one framework or project and want a single environment for all of them. - You need a specific or legacy PHP version. - You want the same stack to go to production with `./laradock ship`, and you can still choose FrankenPHP as the runtime. ## Frequently Asked Questions ### Is Symfony Docker official? It is maintained by KΓ©vin Dunglas, a Symfony core team member, and is the setup the Symfony documentation points to for Docker. It is best described as official-adjacent rather than a first-party Symfony product. ### Can I use FrankenPHP with Laradock? Yes. FrankenPHP is one of Laradock's built-in services (`./laradock start frankenphp`), alongside RoadRunner and the classic NGINX/Apache/Caddy + PHP-FPM options, so choosing Laradock does not mean giving up FrankenPHP. ### Does Symfony Docker handle databases and search? It focuses on the PHP runtime; a database, search engine, or message broker are additions you wire into its `compose.yaml`. Laradock ships those as ready-to-start services. See the full landscape: **[Laradock vs Laravel Sail](https://laradock.io/docs/laradock-vs-laravel-sail)** and **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Run Symfony on Docker](https://laradock.io/docs/symfony-on-docker)** takes about five minutes. ================================================================ # Laradock vs Laravel Valet Source: https://laradock.io/docs/laradock-vs-valet ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Valet? [Laravel Valet](https://laravel.com/docs/valet) is a minimal, official Laravel tool for macOS that configures Nginx and DnsMasq to run natively in the background on your Mac, then proxies requests for any project folder you "park" or "link" to a `.test` domain. There is no virtual machine and no container: everything runs directly on your OS, using roughly 7MB of RAM. It predates (and still underlies parts of) [Laravel Herd](https://laradock.io/docs/laradock-vs-laravel-herd), which is a friendlier GUI wrapper around the same idea. This page compares Valet's native, command-line-only approach to Laradock's containerized one. *Valet is the leanest possible native option: no GUI, no virtual machine, just Nginx and DnsMasq running quietly in the background. Laradock is the leanest possible containerized option: no host installs at all, everything disposable. Both value minimalism; they just draw the line in different places.* **TL;DR:** pick [Valet](https://laravel.com/docs/valet) if you are on macOS, want the absolute lightest native footprint, and are comfortable installing services with Homebrew. Pick Laradock if you want Linux/Windows support, production-like containers, or services beyond what Homebrew conveniently offers. ## Setting up a Laravel app with Valet ```bash composer global require laravel/valet valet install cd ~/Sites valet park laravel new my-app ``` Any project inside a "parked" directory is instantly served at `http://my-app.test`; a single project elsewhere can be exposed with `valet link my-app` instead. Need a database? Valet does not include one, install MySQL or PostgreSQL yourself via Homebrew, or add them through Herd Pro, DBngin, or a container. Switch PHP version per site: ```bash valet use php@8.3 # or drop a .valetphprc file in the project containing "8.3" ``` ## The same thing with Laradock ```bash cd my-app git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` Your site answers at `http://localhost`; MySQL and Redis are one word in the `start` command instead of a separate Homebrew install, and 100+ other services (search, queues, local LLMs) are equally one command away. `./laradock remove` leaves nothing behind, whereas Valet's native services stay installed until you remove them by hand. ## Side by side | | **Laravel Valet** | **Laradock** | |---|---|---| | Platform | macOS only | Linux, macOS, Windows | | Runs as | Native Nginx + DnsMasq | Docker containers | | Install | Composer + Homebrew | Nothing (git clone; only Docker itself) | | Databases, Redis, etc. | Not included; install separately | 100+ services, one command each | | Domains | Automatic `.test` via park/link | Manual, or wire Caddy/Traefik | | PHP versions | Per site (`valet use`, `.valetphprc`) | Per project (`.env`) | | Resource use | ~7MB RAM, always-on background services | Only while containers are running | | Production parity | None (native macOS) | High (Linux containers) | | GUI | None (CLI only); Herd offers one | None (CLI only) | ## Choose Valet if... - You are on macOS and want the smallest possible native footprint with a `.test` domain out of the box. - You are comfortable adding databases and other services yourself via Homebrew. - You do not need Linux or Windows support, or production-like containers. ## Choose Laradock if... - You need Linux or Windows support; Valet is macOS-only (the community [Valet Linux](https://cpriego.github.io/valet-linux/) fork exists but is not official). - You want databases, caches, and 100+ other services pre-wired instead of installed by hand. - You want your local stack to behave like a Linux production server. ## Already on Valet? Migrating takes minutes 1. **Export your database** (installed via Homebrew alongside Valet): `mysqldump -h 127.0.0.1 -u root my_db > backup.sql` 2. **Stop Valet's services** so port 80 frees up: `valet stop` (or `composer global remove laravel/valet` once you're confident). 3. **Add Laradock** next to your code: `git clone https://github.com/laradock/laradock.git && cd laradock && cp .env.example .env` 4. **Start your stack:** `./laradock start nginx mysql redis workspace` (or `docker compose up -d nginx mysql redis workspace`) 5. **Import the database:** `./laradock exec -T mysql mysql -uroot -proot default < ../backup.sql` 6. **Update your app's `.env`:** `DB_HOST=127.0.0.1` becomes `DB_HOST=mysql`; credentials in `mysql/defaults.env`. 7. Your site now answers at `http://localhost` instead of `my-app.test` (or wire an nginx site config to keep a custom domain). ## Frequently Asked Questions ### Is Laravel Valet free? Yes, Valet is free and open-source, maintained by the Laravel team as part of the Laravel ecosystem. ### Does Valet work on Windows or Linux? Officially, no, Valet is macOS-only. A community-maintained fork, [Valet Linux](https://cpriego.github.io/valet-linux/), brings similar functionality to Linux, but it is not part of the official Laravel project. ### Does Valet include a database? No. Valet only handles PHP and the web server; you install MySQL, PostgreSQL, Redis, or anything else separately, typically via Homebrew. ### What is the difference between Valet and Herd? [Laravel Herd](https://laradock.io/docs/laradock-vs-laravel-herd) builds on the same native idea as Valet but adds a menu-bar GUI, easier PHP version switching, and (in the paid Pro tier) managed databases, Xdebug, and mail capture. Valet stays a lean, free, CLI-only tool. ### Can I run multiple PHP versions with Valet? Yes, per site: use `valet use php@8.3` inside a project, or drop a `.valetphprc` file containing the version number so Valet picks it automatically. See the full landscape, including DDEV, Sail, Lando and XAMPP: **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Laradock vs the Official WordPress Docker Setup Source: https://laradock.io/docs/laradock-vs-wordpress-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Unlike Laravel with Sail, WordPress has no single official Docker environment. Instead you have three common paths: the WordPress core team's [`wp-env`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/), the community-maintained [official `wordpress` Docker image](https://hub.docker.com/_/wordpress) wired up with a hand-written `docker-compose.yml`, and vendor images like [Bitnami WordPress](https://hub.docker.com/r/bitnami/wordpress). This page compares those with Laradock. *`wp-env` is a zero-config, plugin/theme-development tool. The official image is a bare building block you wire yourself. Laradock is a full, pre-wired environment with real NGINX/MySQL/Redis and 100+ optional services. This page sets WordPress up on each.* **TL;DR:** use [`wp-env`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) if you build plugins or themes and want a throwaway WordPress in one command. Wire the [official image](https://hub.docker.com/_/wordpress) yourself if your stack is tiny and you enjoy writing compose files. Pick Laradock when you want a production-style stack (real web server, Redis object cache, any PHP version), run more than WordPress, or want the same environment to reach production. ## Setting up with wp-env `wp-env` is a Node package that spins up WordPress + MySQL in Docker with no configuration: ```bash npm -g install @wordpress/env cd my-plugin wp-env start ``` WordPress comes up at `http://localhost:8888`, with your plugin/theme folder mapped in. Configure via a `.wp-env.json` (PHP version, WordPress version, mapped plugins/themes). It is purpose-built for **development of** WordPress extensions, not for running a real site: no NGINX (PHP built-in server), no Redis, no mail catcher, and the service list is fixed. ## Setting up with the official WordPress image You write the compose file yourself: ```yaml services: db: image: mysql:8.0 environment: MYSQL_DATABASE: wordpress MYSQL_ROOT_PASSWORD: secret wordpress: image: wordpress:php8.3-apache ports: ["8080:80"] environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_PASSWORD: secret depends_on: [db] ``` `docker compose up -d` and you are live at `http://localhost:8080`. Full control, but everything beyond WordPress + one database (Redis, a real NGINX config, WP-CLI, a mail catcher, HTTPS) is yours to add and maintain. ## The same thing with Laradock ```bash cd my-site git clone https://github.com/laradock/laradock.git cd laradock ``` ```bash ./laradock start nginx mysql redis workspace ./laradock workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql redis workspace docker compose exec workspace bash ``` The `workspace` container ships WP-CLI, so `wp core download`, `wp config create`, and `wp core install` all work inside it. You get a real NGINX in front, Redis for object caching, and any PHP version from 5.6 to 8.5. Full walkthrough: **[Run WordPress on Docker](https://laradock.io/docs/wordpress-on-docker)**. ## Side by side | | **wp-env** | **Official image** | **Laradock** | |---|---|---|---| | Install | Node + `@wordpress/env` | Nothing (write compose) | Nothing (git clone) | | Config | `.wp-env.json` | Your `docker-compose.yml` | per-service folders + one `.env` | | Web server | PHP built-in server | Apache (image default) | Real NGINX / Apache / Caddy | | Object cache (Redis) | ❌ | Add it yourself | βœ… one word | | WP-CLI | βœ… (`wp-env run cli`) | Add a `wordpress:cli` service | βœ… in `workspace` | | Other services | None (fixed) | Whatever you wire | 100+ (search, queues, mail, monitoring) | | PHP versions | Recent only | Image tags | 5.6 - 8.5 | | Runs non-WordPress projects | ❌ | You'd rewrite the compose | βœ… any PHP project | | Production path | ❌ dev tool | Roll your own | `./laradock ship` β†’ server / Kubernetes / cloud | ## Choose wp-env if... - You develop WordPress plugins, themes, or contribute to core, and want a disposable instance in one command. - You do not need a production-like stack, just WordPress running against your code. ## Choose the official image if... - Your needs are minimal (WordPress + one database) and you like owning a short compose file. - You do not mind wiring Redis, NGINX, WP-CLI, and mail yourself as the project grows. ## Choose Laradock if... - You want a **production-style** local stack: real NGINX, Redis object caching, HTTPS via Caddy/Traefik. - You run WordPress **and** other PHP projects and want one environment for all of them. - You need a specific or legacy PHP version WordPress must run on. - You want the same containers to reach production with `./laradock ship`, not just live on your laptop. ## Frequently Asked Questions ### Does WordPress have an official Docker setup? Not one, but two building blocks: the WordPress core team publishes [`wp-env`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) (aimed at extension/core development) and maintains the [official `wordpress` image](https://hub.docker.com/_/wordpress) on Docker Hub (a bare runtime you wire into a compose file). Neither is a full local-development environment the way Laradock is. ### Is wp-env good for running a real WordPress site? No. `wp-env` is designed for developing plugins, themes, and WordPress core, so it deliberately omits a production-style web server, Redis, and mail. For a site that resembles production, use the official image with your own services, or Laradock. ### Can I add Redis object caching? With `wp-env` and the official image you add it yourself. With Laradock, Redis is one word in the start command (`./laradock start redis`), and the `workspace` container has WP-CLI to install the object-cache drop-in. See the full landscape, including native GUI tools: **[Laradock vs Local WP](https://laradock.io/docs/laradock-vs-local-wp)** and **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)**. Ready to try it? **[Run WordPress on Docker](https://laradock.io/docs/wordpress-on-docker)** takes about five minutes. ================================================================ # Maintenance & Upgrades Source: https://laradock.io/docs/maintenance ================================================================ Keeping Laradock current, and keeping your own customizations tracked alongside it. ## Update Laradock A Laradock update is just newer commits on `master`: new services, version bumps, and fixes. To pull them into your project: 1. Pull the latest: `git pull origin master` (or `git submodule update --remote` if you run Laradock as a submodule). 2. Rebuild so image changes take effect: `./laradock rebuild` (or `docker compose build`). 3. Start again: `./laradock start` (or `docker compose up -d`). :::tip After a big update, skim your `.env` against the refreshed `.env.example`, new services occasionally add new variables. Your `.env` always wins, so nothing is overwritten; you're only checking for options worth turning on. ::: ## Track your own changes To keep your Laradock customizations under version control while still pulling upstream updates: 1. Fork the Laradock repository. 2. Use your fork as a submodule inside your project. 3. Commit your changes to your fork. 4. Pull from the upstream repository periodically to stay current. ## Upgrading from a very old Laradock Only relevant if you're coming from a pre-Docker-Desktop setup (Docker Toolbox / VirtualBox) or Laradock v3: 1. Stop the old Docker VM: `docker-machine stop {default}`. 2. Install [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) or [Windows](https://docs.docker.com/docker-for-windows/). 3. Update Laradock: `git pull origin master`. 4. Use Laradock as usual: `./laradock start nginx mysql` (or `docker compose up -d nginx mysql`). :::warning If the last step fails, rebuild everything with `./laradock rebuild --no-cache` (or `docker compose build --no-cache`). **Warning:** container data might be lost, [back it up first](https://laradock.io/docs/volumes#back-up-a-services-data). ::: ================================================================ # Manual Setup (without the CLI) Source: https://laradock.io/docs/manual-setup ================================================================ Prefer to skip the CLI? Everything it does, you can do by hand with plain `docker compose`, same files, same result. This path is meant for advanced users who want full control over exactly which containers run and how they're configured. For the fast path, see [Getting Started](https://laradock.io/docs/getting-started). 1 - Copy the shared settings template: ```bash cp .env.example .env ``` Set `APP_CODE_PATH_HOST` to your project path (for example `../project-z/`, or `../` to serve [multiple projects](https://laradock.io/docs/multiple-projects)). See [How Laradock configuration works](https://laradock.io/docs/getting-started#how-laradock-configuration-works) for the full model. 2 - Start the containers you need, for example NGINX (web server) and MySQL (database): ```bash docker compose up -d nginx mysql ``` Web-server containers (`nginx`, `apache2`, ...) depend on `php-fpm` and start it automatically, so you don't list it explicitly. Pick any combination from the [available services](https://laradock.io/docs/Intro#supported-services). 3 - Enter the workspace to run Artisan, Composer, PHPUnit, and friends: ```bash docker compose exec --user=laradock workspace bash ``` `--user=laradock` makes files come out owned by you, not root. On Windows PowerShell you can also enter any running container with `docker exec -it {workspace-container-id} bash`. Change the user with `WORKSPACE_PUID` / `WORKSPACE_PGID` in your `.env` (defaults in `workspace/defaults.env`). 4 - Point your app at the database. In your PHP project's `.env`, set the host to the service name: ```env DB_HOST=mysql ``` Use Laradock's default DB credentials from `mysql/defaults.env`, or override them in your `.env` and rebuild. Installing Laravel? See [How to Install Laravel in a Docker Container](https://laradock.io/docs/laravel-on-docker). 5 - Open [http://localhost](http://localhost) (or `http://project-1.test/` etc. if you set up [multiple projects](https://laradock.io/docs/multiple-projects)). :::warning Upgrading from an older Laradock? Rebuild the containers you use to avoid errors, [see how to rebuild a container](https://laradock.io/docs/containers#build-or-rebuild-containers). ::: ================================================================ # Multiple PHP Versions Source: https://laradock.io/docs/multiple-php-versions ================================================================ Laradock builds **one** PHP version by default, `PHP_VERSION` in your `.env`, shared by every PHP container (`php-fpm`, `workspace`, `php-worker`, `laravel-horizon`). There are two very different "multiple versions" needs, and they have different answers. ## Different projects, different versions If each version belongs to a **separate project**, don't run them in one stack. Give each project its own Laradock copy and its own `.env`, then set `PHP_VERSION` per project. Switching a project's version is one line plus a rebuild: ```env PHP_VERSION=7.4 ``` ```bash ./laradock rebuild # or: docker compose build ``` This is the normal, fully-supported setup. See [Running Multiple Projects](https://laradock.io/docs/multiple-projects) for how to keep several Laradock instances (or several sites in one instance) side by side without them clashing. ## Two versions at once, in one stack Sometimes a **single** setup genuinely needs two versions running at the same time, a legacy app on PHP 7.4 next to a new project on PHP 8.3, or one project whose services (microservices) target different versions. For that, use the opt-in `docker-compose.multi-php.yml` overlay. It adds `php-fpm-83` and `workspace-83` alongside your primary services and **changes nothing** about the default single-version setup: if you never load it, it doesn't exist. ```bash docker compose -f docker-compose.yml -f docker-compose.multi-php.yml up -d \ nginx php-fpm workspace php-fpm-83 workspace-83 ``` To avoid repeating the `-f` flags, set this once in your `.env` so every `docker compose` command (and the Laradock CLI) picks up both files: ```env COMPOSE_FILE=docker-compose.yml:docker-compose.multi-php.yml ``` ### Route each site to a version Point a site at a specific version by editing its Nginx config (`nginx/sites/your-site.conf`): ```nginx fastcgi_pass php-fpm-83:9000; ``` Sites left on the default `php-upstream` keep using your primary `php-fpm`. On Apache2, set the matching `SetHandler "proxy:fcgi://php-fpm-83:9000"` in that site's vhost. ### Run CLI on the alternate version ```bash docker compose -f docker-compose.yml -f docker-compose.multi-php.yml exec workspace-83 bash ``` You now have `composer`, `artisan`, and `php` on 8.3 in `workspace-83`, and your primary version in `workspace`. ### Add a third (or fourth) version The alternate services inherit the real `php-fpm` / `workspace` build args via Compose [`extends`](https://docs.docker.com/reference/compose-file/services/#extends), so there is **no duplicated config to maintain**, the only thing overridden is the PHP version. To add another version, copy a pair of blocks in `multi-php/compose.yml` and change `83` to the version you want in both the service name and `LARADOCK_PHP_VERSION`: ```yaml php-fpm-74: extends: file: ../php-fpm/compose.yml service: php-fpm build: context: ../php-fpm args: - LARADOCK_PHP_VERSION=7.4 ``` Queue workers and Horizon on an alternate version follow the identical pattern, extend `php-worker` / `laravel-horizon` the same way. :::tip Each extra version is a full PHP image. Two or three side by side is fine; if you find yourself wanting many, that's a sign the versions belong to separate projects, use one Laradock per project instead (see above). ::: ================================================================ # Running Multiple Projects Source: https://laradock.io/docs/multiple-projects ================================================================ By default each container is named after the current folder (e.g. `laradock_workspace_1`), so one Laradock serves one project. There are two ways to run more than one, pick based on whether the projects should be **isolated** or can **share** a stack. ## One Laradock per project (isolated) To run more than one Laradock on the same machine, set **both** of these per project in your `.env`, or the projects will share the same databases on disk: ```env COMPOSE_PROJECT_NAME=myproject # separates the containers DATA_PATH_HOST=~/.laradock/data-myproject # separates the stored data ``` Each project gets its own containers, its own data, and can run its own PHP version and services independently. This is the cleanest option when projects shouldn't touch each other. ## Many sites from one Laradock (shared) To serve several sites from a **single** Laradock instead, point `APP_CODE_PATH_HOST` at the parent folder and add one web-server config per site: ```env APP_CODE_PATH_HOST=../ ``` For **Nginx** add configs under `nginx/sites`, for **Apache2** under `apache2/sites` (each ships `*.conf.example` samples to copy). Then map the domains in your `hosts` file: ``` 127.0.0.1 project-1.test 127.0.0.1 project-2.test ``` :::tip Local domains Don't use `.dev` for local domains (browsers force HTTPS on it). Use `.localhost`, `.invalid`, `.test`, or `.example` instead. ::: ## Different PHP versions per project Need those projects (or one project's microservices) on **different PHP versions at the same time**? See [Multiple PHP Versions](https://laradock.io/docs/multiple-php-versions). ================================================================ # Networking & Domains Source: https://laradock.io/docs/networking ================================================================ How the pieces of your stack reach each other, how to swap plain `localhost` for a real-looking domain, and how to trust your own certificates inside the workspace. ## Connect your app to a service Inside Laradock's network, every container is reachable by its **service name** used as the hostname. So your application talks to a service by its name, not `localhost`. In your project's `.env`: ```env DB_HOST=mysql REDIS_HOST=redis QUEUE_HOST=beanstalkd ``` The same rule holds for every service: `postgres`, `mongo`, `elasticsearch`, and so on are each reachable at their own name from your app and from inside the `workspace`. Each service's own [service page](https://laradock.io/docs/Intro#supported-services) lists its exact hostname and default port. From your **host** machine (a GUI client, a browser, a tool outside Docker), reach the same services at `localhost` on their published port instead, for example `localhost:3306` for MySQL. To go the other way, from inside a container back to something running on your host, use `host.docker.internal` as the hostname. ## Change a service's port Every service publishes its host port through a variable in your `.env`, so you never edit a compose file to move a port. To serve MySQL on `3307` instead of the default `3306`: ```env MYSQL_PORT=3307 ``` Restart the service for it to take effect. Each service page lists its own port variable, and they all follow the same `_PORT` pattern. ### "Port is already in use" If a container won't start and Docker reports `bind: address already in use`, something else on your host already holds that port, usually a native install of the same software (a local MySQL or Postgres) or another Laradock project. Two ways out: - **Move Laradock's port.** Set a free port in your `.env` (for example `MYSQL_PORT=3307`) and connect to that from the host. The container network is unchanged, so `DB_HOST=mysql` still talks to the service on its standard port. - **Free the port.** Stop whatever else is using it. Find the culprit with `lsof -i :3306` (macOS/Linux) or `netstat -ano | findstr :3306` (Windows). ## Use a custom domain Use a real domain instead of the Docker IP. Assuming your domain is `laravel.test`: 1. Map it to localhost in your `/etc/hosts`: ```bash 127.0.0.1 laravel.test ``` 2. Open `http://laravel.test`. Optionally set the server name in your NGINX config: ```conf server_name laravel.test; ``` ## Add CA certificates To install your own CA certificates, drop them in the `workspace/ca-certificates` folder. They're added to the workspace container's system CA store on build. ================================================================ # Production & Deployment Source: https://laradock.io/docs/production ================================================================ import DocCardList from '@theme/DocCardList'; Laradock's default `docker-compose.yml` is tuned for local development: your code is bind-mounted, Xdebug is available, opcache re-checks files on every request. Production wants the opposite, code baked into an immutable image, Xdebug gone, opcache frozen. The [`production/`](https://github.com/laradock/laradock/tree/master/production) folder does exactly that, for **any** PHP app: Laravel, Symfony, WordPress, Moodle, Drupal, or plain PHP. {/* id kept for backward-compat: ~40 project pages deep-link to #prepare-laradock-for-production */} ## The idea in one line {#prepare-laradock-for-production} **A Docker image is the universal deploy adapter.** You build one hardened image of your app, and every target below already knows how to run it, a server, Kamal, Kubernetes, Fly.io. There is no per-provider magic to learn, and Laradock does not try to be a deployment platform. ## 1. Build the image {#build} ```bash ./laradock ship ``` That resolves your app (from `APP_CODE_PATH_HOST`), writes a safe `.dockerignore` if you don't have one, and builds a production image. Add `--push` to push it to a registry, or pass a tag: `./laradock ship registry.example.com/myapp:1.0 --push`. Prefer plain Docker? It's the same thing: ```bash cp laradock/production/dockerignore.sample .dockerignore docker build -f laradock/production/Dockerfile -t myapp:latest . ``` What you get versus your dev container: code **baked in** (no bind mount), `composer install --no-dev` (skipped automatically if your project has no `composer.json`, so WordPress and Moodle just work), `opcache.validate_timestamps=0`, **no Xdebug**, and a production `php.ini`. Same PHP version and base extensions as dev. The image is **self-contained** (nginx + php-fpm inside) and serves HTTP on `$PORT` (default 8080), so it runs as a single container on any platform, from Kubernetes to Cloud Run. On Apple Silicon `ship` builds `linux/amd64` by default. Check it locally with `docker run -p 8080:8080 myapp:latest`. :::tip[Enabled extra extensions in dev?] If you toggled on things like `redis`, `pdo_pgsql` or `gd`, add them at the `extensions` line in [`production/Dockerfile`](https://github.com/laradock/laradock/tree/master/production/Dockerfile), or point `--build-arg BASE_IMAGE=` at your locally-built laradock php-fpm image for exact parity. ::: ## 2. Deploy it, the image runs anywhere {#deploy} Because it's a standard OCI image, **every target below just runs it**, there is nothing Laradock-specific to install on the server. The only real decision is **who runs the infrastructure**: a managed platform, or you. Each platform has its own step-by-step guide. **Managed clouds** (push the image, they run everything): | Platform | Guide | |----------|-------| | Google Cloud Run | [Deploy to Cloud Run](https://laradock.io/docs/deploy-to-google-cloud-run) | | AWS ECS / Fargate | [Deploy to AWS ECS](https://laradock.io/docs/deploy-to-aws-ecs) | | AWS App Runner | [Deploy to App Runner](https://laradock.io/docs/deploy-to-aws-app-runner) | | Azure Container Apps | [Deploy to Azure](https://laradock.io/docs/deploy-to-azure-container-apps) | | Fly.io | [Deploy to Fly.io](https://laradock.io/docs/deploy-to-fly-io) | | Render | [Deploy to Render](https://laradock.io/docs/deploy-to-render) | | Railway | [Deploy to Railway](https://laradock.io/docs/deploy-to-railway) | | DigitalOcean App Platform | [Deploy to DigitalOcean](https://laradock.io/docs/deploy-to-digitalocean) | | Heroku | [Deploy to Heroku](https://laradock.io/docs/deploy-to-heroku) | **Your own infrastructure** (you run it): | Platform | Guide | |----------|-------| | Kubernetes (EKS / GKE / AKS / DOKS, or your own) | [Deploy to Kubernetes](https://laradock.io/docs/deploy-to-kubernetes) | | Your own servers, no Kubernetes (Kamal) | [Deploy with Kamal](https://laradock.io/docs/deploy-to-kamal) | | A single server (Docker Compose) | [Deploy to a Server](https://laradock.io/docs/deploy-to-a-server) | The flows in brief (each guide above has the full steps): ### Managed platforms: Cloud Run, ECS/Fargate, App Runner, Container Apps {#managed} Same shape everywhere: push the image to that cloud's registry, then point its container service at the image and set your env vars. The platform hands you the load balancer, TLS, autoscaling and rollouts, no compose or manifests to maintain. ```bash # example: AWS ECR (same idea for GCP Artifact Registry / Azure ACR) ./laradock ship 1234567890.dkr.ecr.us-east-1.amazonaws.com/myapp:latest --push # then create an ECS/Fargate service (or App Runner / Cloud Run) from that image ``` **Ready-made configs** live in [`production/providers/`](https://github.com/laradock/laradock/tree/master/production/providers), copy the one you need and fill in image + secrets: | Provider | Config | |----------|--------| | AWS ECS / Fargate | [`aws-ecs-task-definition.json`](https://github.com/laradock/laradock/blob/master/production/providers/aws-ecs-task-definition.json) | | AWS App Runner | [`aws-app-runner.json`](https://github.com/laradock/laradock/blob/master/production/providers/aws-app-runner.json) | | Google Cloud Run | [`google-cloud-run.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/google-cloud-run.yaml) | | Azure Container Apps | [`azure-container-app.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/azure-container-app.yaml) | | Fly.io | [`fly.toml`](https://github.com/laradock/laradock/blob/master/production/providers/fly.toml) | | Render | [`render.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/render.yaml) | | Railway | [`railway.json`](https://github.com/laradock/laradock/blob/master/production/providers/railway.json) | | DigitalOcean App Platform | [`digitalocean-app.yaml`](https://github.com/laradock/laradock/blob/master/production/providers/digitalocean-app.yaml) | | Heroku | [`heroku.yml`](https://github.com/laradock/laradock/blob/master/production/providers/heroku.yml) | | Kamal (your own servers) | [`kamal-deploy.yml`](https://github.com/laradock/laradock/blob/master/production/providers/kamal-deploy.yml) | ### Kubernetes: managed (EKS / GKE / AKS / DOKS) or your own {#kubernetes} Push the image, then apply the reference manifests. Managed clusters give you the control plane; the manifests are identical either way. ```bash kubectl create secret generic app-env --from-env-file=laradock/production/.env kubectl apply -f laradock/production/kubernetes.yaml ``` [`kubernetes.yaml`](https://github.com/laradock/laradock/tree/master/production/kubernetes.yaml) is a deliberately plain starting point: a deployment (the self-contained web container, with resource limits and probes), a service, a TLS-ready ingress (cert-manager), an uploads PVC, plus optional worker, scheduler CronJob, and a migrate Job. ### Your own servers {#self-hosted} **One box** (the 80% case). One self-contained container serves HTTP; point the database and Redis at managed services: ```bash cp laradock/production/.env.example laradock/production/.env # fill real values docker compose -f laradock/production/compose.yml up -d ``` **Several boxes, no Kubernetes** β†’ [Kamal](https://kamal-deploy.org) ships your image with zero-downtime rollovers (`kamal setup`, then `kamal deploy` per release), or Docker Swarm if you prefer. Don't hand-roll deploy scripts. ## 3. What your framework needs on top {#frameworks} Every PHP app is `php-fpm + web server + database`. Frameworks only add optional pieces. Toggle them with compose `--profile` flags, or by deleting the matching Kubernetes block: | App | Worker `--profile worker` | Scheduler/cron `--profile scheduler` | Persistent volume | |------------|:-------------------------:|:------------------------------------:|----------------------| | Laravel | `queue:work` | `schedule:run` | `storage/` | | Symfony | `messenger:consume` | if you use cron | `var/` | | WordPress | β€” | wp-cron or system cron | `wp-content/uploads` | | Moodle | β€” | **required** (`admin/cli/cron.php`) | `moodledata` | | Plain PHP | β€” | β€” | as needed | ```bash docker compose -f laradock/production/compose.yml --profile worker --profile scheduler up -d ``` :::warning[Persistent files] Anything users upload must live on a mounted volume or object storage (S3), never inside the image. A deploy replaces the image and wipes anything written to its filesystem. ::: **Migrations** run once per deploy, before traffic shifts. Compose: `docker compose -f laradock/production/compose.yml run --rm app php artisan migrate --force`. Kubernetes: the `migrate` Job. ## Security {#security} :::danger[Never forward database ports in production] Docker publishes ports on the host unless told otherwise. The production compose file deliberately does **not** expose the database. If you add a database container, do not write: ```yml ports: - "3306:3306" ``` See [Docker and iptables](https://fralef.me/docker-and-iptables.html) for why. ::: - **Database is managed, not a pod.** Run MySQL/Postgres/Redis as managed services (RDS, CloudSQL, ElastiCache). Laradock's database services are for local dev only. - **Secrets** come from real env vars or a secret manager at runtime. Never bake `.env` into the image, that's what the `.dockerignore` is for. ### Pushing to Google Container Registry ```bash gcloud auth configure-docker gcloud auth login ./laradock ship gcr.io/your-project/myapp:latest --push ``` ## Verify it works A smoke test builds the image against a throwaway app and asserts nginx serves a request: ```bash ./laradock/production/smoke-test.sh ``` These files are a **reference**, deliberately plain. Copy them into your project and adjust, they're a starting line, not a framework to learn. ## Deploy to your platform Step-by-step guides for every target: ================================================================ # Chroma Source: https://laradock.io/docs/services/chroma ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Chroma? [Chroma](https://www.trychroma.com) is a lightweight open-source vector database with a simple HTTP API, handy for semantic-search and RAG (retrieval-augmented generation) prototypes where you want something simpler to operate than Weaviate or Qdrant. ## Start Chroma ```bash ./laradock start chroma ``` ```bash docker compose up -d chroma ``` Your data is created on first start and kept between restarts, in the `chroma` Docker volume. ## Stop Chroma Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop chroma ``` ```bash docker compose stop chroma ``` To delete the container entirely (the data in the `chroma` volume is still untouched): ```bash ./laradock remove chroma ``` ```bash docker compose rm -sf chroma ``` ## Configuration All settings live in `chroma/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `CHROMA_VERSION` | `latest` | Image tag from the [`chromadb/chroma`](https://hub.docker.com/r/chromadb/chroma) Docker Hub image. | | `CHROMA_HOST_PORT` | `8001` | Host-side port mapped to the Chroma HTTP API (container port `8000`). | Data persists in the `chroma` named Docker volume at `/data` across restarts, it is not a `DATA_PATH_HOST` bind mount like the SQL databases, so you won't find it as a plain folder on your host. ## Change the Chroma version Set the version in your `.env`: ```env CHROMA_VERSION=0.5.20 ``` Then apply the change: ```bash ./laradock rebuild chroma ``` ```bash docker compose build chroma ``` Then start it again to pick up the new image: `./laradock start chroma`. Your collections live in the `chroma` volume, separate from the image, so a version bump doesn't touch them by itself, but Chroma has changed its on-disk storage format across major versions before. [Back up](#backup-and-restore) before jumping multiple major versions, just in case. ## Connect The API is at `http://localhost:8001` from your host. Heartbeat check: `/api/v2/heartbeat`. From another container, use `http://chroma:8000`, note the internal port is `8000`, different from the host-mapped `8001`. ## Backup and restore Chroma's data lives in the `chroma` Docker-managed volume, not a `DATA_PATH_HOST` folder, so back it up by mounting that volume into a throwaway helper container instead of copying files directly off your host. **Export (back up)** everything to a `.tar.gz` on your host (Chroma must be running so its container can be found): ```bash docker run --rm --volumes-from "$(docker compose ps -q chroma)" -v "$(pwd):/backup" alpine tar czf /backup/chroma-backup.tar.gz -C /data . ``` **Restore (import)** into a Chroma container whose `/data` is empty (for example right after [starting completely fresh](#start-completely-fresh-wipe-all-data)): ```bash docker run --rm --volumes-from "$(docker compose ps -q chroma)" -v "$(pwd):/backup" alpine sh -c "cd /data && tar xzf /backup/chroma-backup.tar.gz" ``` For a perfectly consistent snapshot under active writes, stop Chroma first (`./laradock stop chroma`), back up, then start it again; for casual prototype use it's fine to back up while it's running. ## Reset all collections (wipe data, keep the container) Chroma has a built-in reset endpoint that deletes every collection without recreating the container, but it's disabled by default. Enable it in `chroma/defaults.env` or override it in your own `.env`: ```env ALLOW_RESET=TRUE ``` Apply the setting: ```bash ./laradock restart chroma ``` ```bash docker compose restart chroma ``` Then call the reset endpoint: ```bash curl -X POST http://localhost:8001/api/v2/reset ``` This deletes every collection immediately, with no confirmation prompt. Set `ALLOW_RESET` back to `FALSE` (or remove the override) afterward if you don't want the endpoint reachable. ## Start completely fresh (wipe all data) To throw away every collection and start Chroma from a clean, empty volume (⚠️ this **permanently deletes** everything in the `chroma` volume, [back up](#backup-and-restore) first if you need anything): ```bash ./laradock stop chroma ./laradock remove chroma docker volume rm $(docker volume ls -q --filter label=com.docker.compose.volume=chroma) ./laradock start chroma ``` ```bash docker compose stop chroma docker compose rm -sf chroma docker volume rm $(docker volume ls -q --filter label=com.docker.compose.volume=chroma) docker compose up -d chroma ``` If you run more than one Laradock project on the same machine, also filter by `--filter label=com.docker.compose.project=` so you don't delete a different project's `chroma` volume by mistake. ## Talk to this Chroma from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Chroma by container name out of the box. Easiest fix: use the published port (`CHROMA_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `chroma`, for example `http://host.docker.internal:8001` (Docker Desktop). Make sure the two projects use different `CHROMA_HOST_PORT` values if they're both running at once. ## Common issues - **Confusing host vs container port.** The container listens on `8000` internally; `CHROMA_HOST_PORT` (`8001`) is only the host-side mapping. From other containers, always use port `8000`. - **Data disappeared after recreating the container.** Data lives in the `chroma` named volume; running `docker compose down -v` (which removes named volumes) rather than `./laradock remove chroma` wipes it. - **Port already in use on your host.** Change `CHROMA_HOST_PORT` in `.env` and restart: `./laradock start chroma`. - **App can't connect but the container is running.** Use the container name `chroma`, not `localhost`, from inside another container. - **`/api/v2/reset` returns an error.** The reset endpoint is disabled unless `ALLOW_RESET=TRUE` is set (see [Reset all collections](#reset-all-collections-wipe-data-keep-the-container) above), and requires a restart after changing it. --- Comparing vector databases? See **[Qdrant](https://laradock.io/docs/services/qdrant)** and **[Weaviate](https://laradock.io/docs/services/weaviate)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Flowise Source: https://laradock.io/docs/services/flowise ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Flowise? [Flowise](https://flowiseai.com) is a visual, low-code builder for LLM apps and AI agents. Prototype agent and RAG flows by dragging nodes together in its editor, then call the resulting flow from Laravel over HTTP. ## Start Flowise ```bash ./laradock start flowise ``` ```bash docker compose up -d flowise ``` ## Stop Flowise Stopping just pauses the container; **your flows are safe** (kept in the `flowise` Docker volume): ```bash ./laradock stop flowise ``` ```bash docker compose stop flowise ``` To delete the container entirely (the `flowise` volume, and everything in it, is still untouched): ```bash ./laradock remove flowise ``` ```bash docker compose rm -sf flowise ``` ## Configuration All settings live in `flowise/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `FLOWISE_VERSION` | `latest` | Image tag from the [`flowiseai/flowise`](https://hub.docker.com/r/flowiseai/flowise) Docker Hub image. | | `FLOWISE_HOST_PORT` | `3020` | Host-side port the Flowise builder/API is published on (container port `3000`). | Flows, credentials, and chat history persist in the `flowise` volume at `/root/.flowise` across restarts. ## Change the Flowise version Set the version in your `.env`: ```env FLOWISE_VERSION=latest ``` Then apply the change: ```bash ./laradock rebuild flowise ``` ```bash docker compose build flowise ``` Flows and credentials live in the `flowise` volume, separate from the image, so changing versions doesn't touch your data. Restart the container after rebuilding: `./laradock restart flowise`. ## Connect Open the builder at [http://localhost:3020](http://localhost:3020). Health check: `/api/v1/ping` returns `pong`. Once you've built a flow, call it from your app via its prediction API endpoint (shown in the Flowise UI for that flow); from inside another container that's reachable at `http://flowise:3000`. ## Backup and restore Flowise stores flows, credentials, and chat history in a named Docker volume (not a bind-mounted host folder), so back it up by copying the container's data directory out to your host while the container is running: ```bash ./laradock cp flowise:/root/.flowise ./flowise-backup ``` ```bash docker compose cp flowise:/root/.flowise ./flowise-backup ``` To restore, copy a backup folder back in (the container must already exist), then restart: ```bash ./laradock cp ./flowise-backup/. flowise:/root/.flowise ``` ```bash docker compose cp ./flowise-backup/. flowise:/root/.flowise ``` Restart afterward: `./laradock restart flowise`. ## Start completely fresh (wipe all data) To throw away every flow, credential, and chat history and start Flowise from a clean, empty state (⚠️ this **permanently deletes** everything in the `flowise` volume, back up first if you need anything): ```bash ./laradock stop flowise ./laradock remove flowise docker volume rm $(docker volume ls -q --filter name=flowise) ./laradock start flowise ``` ```bash docker compose stop flowise docker compose rm -sf flowise docker volume rm $(docker volume ls -q --filter name=flowise) docker compose up -d flowise ``` Flowise's data lives in a named Docker volume, not a `DATA_PATH_HOST` folder, so removing the container alone doesn't touch it, you have to remove the volume too. The filter matches on the volume name containing `flowise`, if you run multiple Laradock projects on the same machine, check `docker volume ls | grep flowise` first and remove the exact one for this project. ## Common issues - **Builder loads but a flow's API calls fail.** Confirm the flow is saved and, if it uses an external provider (OpenAI, Anthropic, etc.), that the corresponding credentials are configured in Flowise's credential store, not just typed into a node. - **Can't reach the API from your Laravel app.** From inside another container, use `http://flowise:3000`, not `localhost:3020`, the host port only applies from outside Docker. - **Port already in use on your host.** Change `FLOWISE_HOST_PORT` in `.env` and restart: `./laradock restart flowise`. - **Flows disappeared after recreating the container.** Data lives in the `flowise` named volume, not the container itself, so `./laradock remove flowise` followed by `./laradock start flowise` is safe. It's only gone if the volume itself was removed (see [Start completely fresh](#start-completely-fresh-wipe-all-data) above), or if you ran raw `docker compose down -v` for the whole project, which removes volumes for every service. --- Want a more general-purpose automation/workflow tool alongside AI nodes? See **[n8n](https://laradock.io/docs/services/n8n)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Langflow Source: https://laradock.io/docs/services/langflow ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Langflow? [Langflow](https://langflow.org) is a visual builder for LLM apps and AI agents. You wire components together on a canvas, then call the finished flow from Laravel over HTTP. Its components are plain Python, so you can drop into code for a custom step instead of being limited to the built-in nodes. Langflow and **[Flowise](https://laradock.io/docs/services/flowise)** solve the same problem in different ecosystems, the same way Laradock ships both MySQL and PostgreSQL. Pick whichever fits: Langflow if you want Python-native components, Flowise if you want a Node-based builder. ## Start Langflow ```bash ./laradock start langflow ``` ```bash docker compose up -d langflow ``` First boot takes a minute or two while Langflow initializes its database. ## Stop Langflow Stopping just pauses the container; **your flows are safe** (kept in the `langflow` Docker volume): ```bash ./laradock stop langflow ``` ```bash docker compose stop langflow ``` To delete the container entirely (the `langflow` volume, and everything in it, is still untouched): ```bash ./laradock remove langflow ``` ```bash docker compose rm -sf langflow ``` ## Configuration All settings live in `langflow/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `LANGFLOW_VERSION` | `latest` | Image tag from the [`langflowai/langflow`](https://hub.docker.com/r/langflowai/langflow) Docker Hub image. | | `LANGFLOW_HOST_PORT` | `3021` | Host-side port the Langflow builder/API is published on (container port `7860`). | | `LANGFLOW_SUPERUSER` | `admin` | Username for the Langflow admin account. | | `LANGFLOW_SUPERUSER_PASSWORD` | `secret` | Password for the Langflow admin account. **Change this if the port is reachable by anyone but you.** | Langflow refuses to boot without a superuser set, so Laradock ships `admin` / `secret` by default to keep first run zero-config. Those defaults are for local development only, override both in your `.env` before exposing Langflow beyond localhost. The account is created from these values on **first boot only**, when the database in the `langflow` volume is initialized. Changing them later won't update an existing account; change the password from inside the Langflow UI, or wipe the volume (see [Start completely fresh](#start-completely-fresh-wipe-all-data)) to re-seed. Flows, credentials, and run history persist in the `langflow` volume at `/app/langflow` across restarts. ## Change the Langflow version Set the version in your `.env`: ```env LANGFLOW_VERSION=latest ``` Then apply the change: ```bash ./laradock rebuild langflow ``` ```bash docker compose build langflow ``` Flows and credentials live in the `langflow` volume, separate from the image, so changing versions doesn't touch your data. Restart the container after rebuilding: `./laradock restart langflow`. ## Connect Open the builder at [http://localhost:3021](http://localhost:3021) and log in with `admin` / `secret` (or whatever you set `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` to). Health check: `/health` returns `{"status":"ok"}`. Once you've built a flow, call it from your app at `/api/v1/run/{flow_id}` (the Langflow UI shows the exact endpoint and payload for each flow under its API panel); from inside another container that's reachable at `http://langflow:7860`. ## Use it with the rest of your stack Langflow talks to the other Laradock AI services over the `backend` network, so point its components at container names rather than `localhost`: - **[Ollama](https://laradock.io/docs/services/ollama)** for local models: `http://ollama:11434` - **[Qdrant](https://laradock.io/docs/services/qdrant)** for vector storage: `http://qdrant:6333` - **[LiteLLM](https://laradock.io/docs/services/litellm)** as one OpenAI-compatible endpoint in front of every provider: `http://litellm:4000` ## Backup and restore Langflow stores flows, credentials, and run history in a named Docker volume (not a bind-mounted host folder), so back it up by copying the container's data directory out to your host while the container is running: ```bash ./laradock cp langflow:/app/langflow ./langflow-backup ``` ```bash docker compose cp langflow:/app/langflow ./langflow-backup ``` To restore, copy a backup folder back in (the container must already exist), then restart: ```bash ./laradock cp ./langflow-backup/. langflow:/app/langflow ``` ```bash docker compose cp ./langflow-backup/. langflow:/app/langflow ``` Restart afterward: `./laradock restart langflow`. ## Start completely fresh (wipe all data) To throw away every flow, credential, and run history and start Langflow from a clean, empty state (⚠️ this **permanently deletes** everything in the `langflow` volume, back up first if you need anything): ```bash ./laradock stop langflow ./laradock remove langflow docker volume rm $(docker volume ls -q --filter name=langflow) ./laradock start langflow ``` ```bash docker compose stop langflow docker compose rm -sf langflow docker volume rm $(docker volume ls -q --filter name=langflow) docker compose up -d langflow ``` Langflow's data lives in a named Docker volume, not a `DATA_PATH_HOST` folder, so removing the container alone doesn't touch it, you have to remove the volume too. The filter matches on the volume name containing `langflow`, if you run multiple Laradock projects on the same machine, check `docker volume ls | grep langflow` first and remove the exact one for this project. ## Common issues - **Builder is blank or errors on first load.** Langflow initializes its database on first boot and the UI can be reachable before that finishes. Give it a minute, then reload; check progress with `./laradock logs langflow`. - **Container keeps restarting with `ValueError: Username and password must be set`.** Langflow won't boot without a superuser. Laradock sets one in `langflow/defaults.env`, so this means both values resolved to empty, usually from an override in your own `.env`. Set `LANGFLOW_SUPERUSER` and `LANGFLOW_SUPERUSER_PASSWORD` to non-empty values. Note Langflow also rejects its own legacy default password (`langflow`), pick anything else. - **Login fails with the credentials in your `.env`.** The account is seeded on first boot only. If you changed the values after the volume already existed, the old account is still in force. Change the password in the UI, or wipe the volume to re-seed. - **Can't reach the API from your Laravel app.** From inside another container, use `http://langflow:7860`, not `localhost:3021`, the host port only applies from outside Docker. - **A flow can't reach Ollama or a vector DB.** Use the container name (`http://ollama:11434`), not `localhost`. Inside the Langflow container, `localhost` is Langflow itself. - **Port already in use on your host.** Change `LANGFLOW_HOST_PORT` in `.env` and restart: `./laradock restart langflow`. - **Flows disappeared after recreating the container.** Data lives in the `langflow` named volume, not the container itself, so `./laradock remove langflow` followed by `./laradock start langflow` is safe. It's only gone if the volume itself was removed (see [Start completely fresh](#start-completely-fresh-wipe-all-data) above), or if you ran raw `docker compose down -v` for the whole project, which removes volumes for every service. --- Prefer a Node-based builder for the same job? See **[Flowise](https://laradock.io/docs/services/flowise)**. Want general-purpose automation with AI nodes attached? See **[n8n](https://laradock.io/docs/services/n8n)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # LiteLLM Source: https://laradock.io/docs/services/litellm ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is LiteLLM? [LiteLLM](https://litellm.ai) is an LLM proxy/gateway exposing one OpenAI-compatible endpoint that routes to any provider, the backbone of agentic apps needing a unified API and key management across OpenAI, Anthropic, Ollama, and dozens of other backends. ## Start LiteLLM ```bash ./laradock start litellm ``` ```bash docker compose up -d litellm ``` Before starting, edit `litellm/config.yaml` to add your models/providers. A commented-out Ollama example is included in that file to get you started. ## Stop LiteLLM ```bash ./laradock stop litellm ``` ```bash docker compose stop litellm ``` To remove the container: ```bash ./laradock remove litellm ``` ```bash docker compose rm -sf litellm ``` LiteLLM keeps no data volume of its own (no database is wired up by default), so there's nothing to back up or wipe: removing the container just drops it, `litellm/config.yaml` on your host is untouched. ## Configuration All settings live in `litellm/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `LITELLM_VERSION` | `main-latest` | Image tag from [`ghcr.io/berriai/litellm`](https://github.com/BerriAI/litellm/pkgs/container/litellm). | | `LITELLM_HOST_PORT` | `4000` | Host-side port LiteLLM is published on (container port `4000`). | | `LITELLM_MASTER_KEY` | `sk-laradock` | Auth key required on every request to the proxy. | `litellm/config.yaml` is bind-mounted straight into the container at `/app/config.yaml`, so edits on your host take effect on the next container restart, no rebuild needed. ## Add a provider `litellm/config.yaml` ships with a `mock-gpt` entry so the proxy works out of the box with no keys. To route to a real provider, add a block to `model_list`, referencing the provider's API key via an environment variable rather than hardcoding it in the file: ```yaml model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY ``` Set `OPENAI_API_KEY` (or whichever provider's key) in your `.env`, and pass it through to the container by adding it under `environment:` in `litellm/compose.yml`. Then restart to pick up the config change: ```bash ./laradock restart litellm ``` ```bash docker compose restart litellm ``` The commented-out Ollama block already in `config.yaml` follows the same pattern (`ollama/llama3.2` with `api_base: http://ollama:11434`), uncomment it once the [Ollama](https://laradock.io/docs/services/ollama) service has that model pulled. ## Change the LiteLLM version Set the version in your `.env`: ```env LITELLM_VERSION=v1.55.0 ``` `litellm` runs a pulled image, not a local build, so pull the new tag first: ```bash docker compose pull litellm ``` Then recreate the container on it: ```bash ./laradock start litellm ``` ```bash docker compose up -d litellm ``` ## Connect The proxy is at `http://localhost:4000` from your host, or `http://litellm:4000` from other containers. Health check: `/health/liveliness`. Authenticate requests with `LITELLM_MASTER_KEY` (default `sk-laradock`) as a Bearer token, same as an OpenAI API key. ## Test the proxy Send a chat completion request using the built-in `mock-gpt` model (works with no provider keys configured, good for confirming the proxy itself is up): ```bash curl http://localhost:4000/v1/chat/completions \ -H "Authorization: Bearer sk-laradock" \ -H "Content-Type: application/json" \ -d '{"model": "mock-gpt", "messages": [{"role": "user", "content": "hello"}]}' ``` Swap `mock-gpt` for any `model_name` you've added to `config.yaml`, and `sk-laradock` for your own `LITELLM_MASTER_KEY` if you've changed it. ## List available models ```bash curl http://localhost:4000/v1/models \ -H "Authorization: Bearer sk-laradock" ``` Returns every `model_name` currently defined in `litellm/config.yaml`, useful for confirming a config edit actually took effect after a restart. ## Talk to this gateway from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this LiteLLM by container name out of the box. Easiest fix: publish the port (already done, `LITELLM_HOST_PORT`) and have the other project's app call your **host machine's** address instead of `litellm`, for example `http://host.docker.internal:4000` (Docker Desktop) with the same `LITELLM_MASTER_KEY`. This is a reasonable way to run one shared gateway (with your real provider keys configured once) for multiple local projects, instead of duplicating provider credentials per project. Make sure the two projects use different `LITELLM_HOST_PORT` values if they're both running at once. ## Common issues - **401 on every request.** Missing or wrong `Authorization: Bearer ` header. - **Config changes don't take effect.** `litellm/config.yaml` is read at container start; run `./laradock restart litellm` after editing. - **Requests to a provider fail even though the proxy is up.** LiteLLM only routes to what's configured in `config.yaml`, if a model/provider isn't listed there (with its own API key, where required), requests for it will fail. Uncomment and adapt the included Ollama example, or add your own provider block. - **App can't connect but the container is running.** Use the container name `litellm`, not `localhost`, from inside another container. --- Only need one local model backend, not a multi-provider gateway? See **[Ollama](https://laradock.io/docs/services/ollama)** or **[LocalAI](https://laradock.io/docs/services/localai)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # LocalAI Source: https://laradock.io/docs/services/localai ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is LocalAI? [LocalAI](https://localai.io) is a free, self-hosted drop-in replacement for the OpenAI REST API, covering LLMs, embeddings, and image generation on your own hardware. It's aimed at apps already coded against the OpenAI API that need to run entirely offline or on-prem. ## Start LocalAI ```bash ./laradock start localai ``` ```bash docker compose up -d localai ``` ## Stop LocalAI Stopping just pauses the container; downloaded models are safe (kept in the `localai` Docker volume): ```bash ./laradock stop localai ``` ```bash docker compose stop localai ``` To delete the container entirely (the `localai` volume, and any models in it, are still untouched): ```bash ./laradock remove localai ``` ```bash docker compose rm -sf localai ``` ## Configuration All settings live in `localai/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `LOCALAI_VERSION` | `latest` | Image tag from the [`localai/localai`](https://hub.docker.com/r/localai/localai) Docker Hub image. | | `LOCALAI_HOST_PORT` | `8088` | Host-side port LocalAI is published on (container port `8080`). | Models are stored in the `localai` named Docker volume at `/models`, not under `DATA_PATH_HOST`, so they persist across restarts but aren't visible directly on your host filesystem. ## Change the LocalAI version Set the version in your `.env` (pick a tag from the Docker Hub page linked above, instead of the default `latest`): ```env LOCALAI_VERSION= ``` Then apply the change: ```bash ./laradock rebuild localai ``` ```bash docker compose build localai ``` ## Load a model No models are bundled with the image, so `/v1/models` returns an empty list until you add one. LocalAI reads models from `/models` inside the container, which is the `localai` volume. Copy a model file you've already downloaded straight into the running container: ```bash docker cp ./your-model.gguf localai:/models/your-model.gguf ``` Then confirm it shows up: ```bash curl http://localhost:8088/v1/models ``` For discovering and pulling preconfigured models by name instead of sourcing files yourself, see LocalAI's own [model gallery docs](https://localai.io/models/). ## Connect The API is at `http://localhost:8088` from your host. Readiness check: `/readyz`; list loaded models: `/v1/models`. From another container, use `http://localai:8080/v1` as the OpenAI-compatible base URL, note the internal port is `8080`, different from the host-mapped `8088`. ## Backup and restore Models live in the `localai` named Docker volume rather than a `DATA_PATH_HOST` folder, so backing them up means archiving the volume itself. Find its full name first (Docker prefixes it with your project name): ```bash docker volume ls | grep localai ``` **Back up** the volume to a `.tar.gz` on your host (replace `` with what you found above): ```bash docker run --rm -v :/models -v "$(pwd)":/backup alpine tar czf /backup/localai-models-backup.tar.gz -C /models . ``` **Restore** it into a volume of the same name: ```bash docker run --rm -v :/models -v "$(pwd)":/backup alpine tar xzf /backup/localai-models-backup.tar.gz -C /models ``` This uses a throwaway `alpine` container just to reach the volume; LocalAI itself doesn't need to be running for either step. Worth doing before wiping the volume or moving to a new machine, since large models can take a long time to re-download. ## Start completely fresh (wipe all data) To throw away every downloaded model and start LocalAI from a clean, empty volume (⚠️ this **permanently deletes** everything in it, back up first if you need anything): ```bash ./laradock stop localai ./laradock remove localai docker volume rm ./laradock start localai ``` ```bash docker compose stop localai docker compose rm -sf localai docker volume rm docker compose up -d localai ``` Use `docker volume ls | grep localai` (as above) to get the exact `` for your project first. ## Common issues - **`/v1/models` returns an empty list.** No models are bundled by default, [load one](#load-a-model) into the `localai` volume before the API has anything to serve. - **Confusing host vs container port.** The container listens on `8080` internally; `LOCALAI_HOST_PORT` (`8088`) is only the host-side mapping. From other containers, always use port `8080`. - **Slow responses on CPU-only hosts.** Like most local inference servers, LocalAI benefits heavily from GPU acceleration; expect slower throughput without it. - **App can't connect but the container is running.** Use the container name `localai`, not `localhost`, from inside another container. --- Prefer Ollama's simpler model-pull workflow? See **[Ollama](https://laradock.io/docs/services/ollama)**. Need to route between multiple providers behind one endpoint? See **[LiteLLM](https://laradock.io/docs/services/litellm)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MCP Source: https://laradock.io/docs/services/mcp ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MCP? [MCP](https://modelcontextprotocol.io) (Model Context Protocol) is the standard way AI coding agents connect to external tools. Laradock's `mcp` service runs [DBHub](https://github.com/bytebase/dbhub), a database MCP server, so agents like Claude Code and Cursor can inspect your schema and query your data directly instead of guessing at your table structure. Your agent already reads your code from disk. What it can't see is your database. This closes that gap: ask *"why is this query slow?"* or *"what columns does the orders table have?"* and the agent looks at the real schema rather than inferring it from your migrations. Queries are **read-only by default**: agents can `SELECT`, never `INSERT`, `UPDATE`, `DELETE`, or `DROP`. ## Start MCP The `mcp` service exposes a database, so start one alongside it: ```bash ./laradock start mcp mysql ``` ```bash docker compose up -d mcp mysql ``` `mcp` points at MySQL out of the box. To expose a different database, change `MCP_DSN` (see [Point at a different database](#point-at-a-different-database)). ## Stop MCP ```bash ./laradock stop mcp ``` ```bash docker compose stop mcp ``` To remove the container: ```bash ./laradock remove mcp ``` ```bash docker compose rm -sf mcp ``` `mcp` stores nothing of its own: it reads whichever database `MCP_DSN` points at. Removing the container touches no data. ## Configuration All settings live in `mcp/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MCP_VERSION` | `latest` | Image tag from [`bytebase/dbhub`](https://hub.docker.com/r/bytebase/dbhub). | | `MCP_HOST_PORT` | `8321` | Host-side port the MCP server is published on (container port `8080`). | | `MCP_DSN` | `mysql://default:secret@mysql:3306/default` | Which database to expose, as a connection string. | `mcp/dbhub.toml` is bind-mounted into the container and controls which tools agents get. Edits take effect on the next restart, no rebuild needed. ## Connect your agent The server speaks MCP over HTTP at `http://localhost:8321/mcp`. ### Claude Code ```bash claude mcp add --transport http laradock-db http://localhost:8321/mcp ``` Or commit it to your project by creating `.mcp.json` in your project root, so the whole team picks it up: ```json { "mcpServers": { "laradock-db": { "type": "http", "url": "http://localhost:8321/mcp" } } } ``` ### Cursor Create `.cursor/mcp.json` in your project root: ```json { "mcpServers": { "laradock-db": { "url": "http://localhost:8321/mcp" } } } ``` ### Anything else Any MCP client supporting HTTP transport works. Point it at `http://localhost:8321/mcp`. Once connected, your agent gets two tools: | Tool | What it does | |---|---| | `search_objects` | Explore tables, columns, and indexes. | | `execute_sql` | Run a read-only query (max 1000 rows). | ## Point at a different database `MCP_DSN` accepts MySQL, MariaDB, PostgreSQL, SQL Server, and SQLite. The host is the Laradock service name, so start that service too. Set it in your `.env`: ```env MCP_DSN=postgres://default:secret@postgres:5432/default ``` Then start both: ```bash ./laradock start mcp postgres ``` ```bash docker compose up -d mcp postgres ``` Other formats follow the same shape: ```env MCP_DSN=mariadb://default:secret@mariadb:3306/default MCP_DSN=sqlserver://sa:yourStrong(!)Password@mssql:1433/master ``` ## Let agents write to the database Off by default, and worth keeping that way: an agent that can `DROP TABLE` eventually will. If you do want it, edit `mcp/dbhub.toml` and remove the `readonly` line: ```toml [[tools]] name = "execute_sql" source = "laradock" max_rows = 1000 ``` Then restart: ```bash ./laradock restart mcp ``` ```bash docker compose restart mcp ``` Only do this against a local development database you can afford to lose. ## Test the server Confirm it's up and can reach your database, without wiring up an agent first: ```bash curl -s http://localhost:8321/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' ``` A JSON response naming `dbhub` means the server is running and connected. ## Change the MCP version Set the version in your `.env`: ```env MCP_VERSION=0.23.0 ``` `mcp` runs a pulled image, not a local build, so pull the new tag first: ```bash docker compose pull mcp ``` Then recreate the container on it: ```bash ./laradock start mcp ``` ```bash docker compose up -d mcp ``` ## Common issues - **Container keeps restarting.** It exits when the database isn't reachable and retries until it is. If it never settles, the database named in `MCP_DSN` probably isn't running: start it (`./laradock start mysql`). Check with `./laradock logs mcp`. - **`ECONNREFUSED` in the logs.** The host in `MCP_DSN` must be the Laradock service name (`mysql`, `postgres`), not `localhost`. From inside a container, `localhost` is that container itself. - **Agent doesn't see the tools.** Confirm the container is running (`./laradock logs mcp`), then restart your agent: most MCP clients only connect at startup. - **"Read-only mode is enabled" error.** Working as intended, the agent tried to write. See [Let agents write to the database](#let-agents-write-to-the-database) if that's genuinely what you want. - **Port 8321 already taken.** Change `MCP_HOST_PORT` in your `.env` and update your agent's config URL to match. --- Want a local LLM to go with it? See **[Ollama](https://laradock.io/docs/services/ollama)**. Building AI features on your data? Pair it with a vector database like **[pgvector](https://laradock.io/docs/services/pgvector)** or **[Qdrant](https://laradock.io/docs/services/qdrant)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # n8n Source: https://laradock.io/docs/services/n8n ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is n8n? [n8n](https://n8n.io) is a workflow-automation platform with first-class AI/agent nodes. Build agentic flows visually in its editor and call your app's webhooks from them, or trigger n8n workflows from your app. ## Start n8n ```bash ./laradock start n8n ``` ```bash docker compose up -d n8n ``` Workflows, credentials, and execution history persist in the `n8n` Docker volume across restarts. Name any other services alongside it to start them together, for example `./laradock start n8n redis`. ## Stop n8n Stopping just pauses the container; **your workflows are safe**: ```bash ./laradock stop n8n ``` ```bash docker compose stop n8n ``` To delete the container entirely (the `n8n` volume, and everything in it, is still untouched): ```bash ./laradock remove n8n ``` ```bash docker compose rm -sf n8n ``` ## Configuration All settings live in `n8n/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `N8N_VERSION` | `latest` | Image tag from the [`n8nio/n8n`](https://hub.docker.com/r/n8nio/n8n) Docker Hub image. | | `N8N_HOST_PORT` | `5678` | Host-side port the n8n editor/API is published on (container port `5678`). | `n8n/compose.yml` also sets `N8N_SECURE_COOKIE=false` directly in the container environment, so the editor works over plain `http://localhost` without HTTPS, fine for local dev, not for a public deployment. ## Change the n8n version Set the version in your `.env`: ```env N8N_VERSION=1.60.0 ``` Then apply the change: ```bash ./laradock rebuild n8n ``` ```bash docker compose build n8n ``` ## Connect Open the editor at [http://localhost:5678](http://localhost:5678). On first visit n8n asks you to create the owner account (email/password), that account is stored in the `n8n` volume, not in an env var. Health check: `/healthz`. ## Backup and restore Workflows and credentials live inside the `n8n` volume as a SQLite database, together with the encryption key n8n generated on first boot to encrypt saved credentials. **Keep that volume (or a backup of it) together with any exported credentials**, restoring credentials into a container with a different encryption key leaves them undecryptable. **Export all workflows** to a JSON file, then copy it out to your host: ```bash ./laradock exec -T n8n n8n export:workflow --all --output=/tmp/n8n-workflows.json ``` ```bash docker compose exec -T n8n n8n export:workflow --all --output=/tmp/n8n-workflows.json ``` ```bash docker compose cp n8n:/tmp/n8n-workflows.json ./n8n-workflows.json ``` **Export all credentials** the same way (add `--decrypted` only if you intend to import into a container with the *same* encryption key, otherwise leave them encrypted): ```bash ./laradock exec -T n8n n8n export:credentials --all --output=/tmp/n8n-credentials.json ``` ```bash docker compose exec -T n8n n8n export:credentials --all --output=/tmp/n8n-credentials.json ``` ```bash docker compose cp n8n:/tmp/n8n-credentials.json ./n8n-credentials.json ``` **Restore** by copying the file back in and importing it: ```bash docker compose cp ./n8n-workflows.json n8n:/tmp/n8n-workflows.json ``` ```bash ./laradock exec -T n8n n8n import:workflow --input=/tmp/n8n-workflows.json ``` ```bash docker compose exec -T n8n n8n import:workflow --input=/tmp/n8n-workflows.json ``` Use `import:credentials --input=...` the same way for the credentials file. ## Start completely fresh (wipe all data) To throw away every workflow, credential, and execution and start n8n from a clean, empty state (⚠️ this **permanently deletes** everything in the `n8n` volume, [back up](#backup-and-restore) first if you need anything): ```bash ./laradock stop n8n ./laradock remove n8n ``` ```bash docker compose stop n8n docker compose rm -sf n8n ``` Then remove the underlying volume (n8n's data is a named Docker volume, not a folder under `DATA_PATH_HOST`, so find its exact project-prefixed name first): ```bash docker volume ls | grep n8n docker volume rm ``` ```bash ./laradock start n8n ``` ```bash docker compose up -d n8n ``` Starting again re-creates the volume and re-runs first-boot setup, including the owner-account prompt in the editor. ## Common issues - **Editor won't load or shows a cookie/session error.** Confirm you're accessing it over plain HTTP on `localhost`; `N8N_SECURE_COOKIE=false` is set for that case. Accessing it over HTTPS or a different host may need adjusting that setting. - **Webhook from n8n to your Laravel app fails.** From inside the `n8n` container, reach your app by its Laradock container name (e.g. `http://nginx` or `http://php-fpm`), not `localhost`. - **Webhook from your app to n8n fails.** From inside another container, reach n8n at `http://n8n:5678`, not `localhost:5678`. - **Port already in use on your host.** Change `N8N_HOST_PORT` in `.env` and restart: `./laradock restart n8n`. - **Imported credentials show as invalid.** The encryption key used to export them doesn't match the target container's key, see the note in [Backup and restore](#backup-and-restore). --- Want a lower-code way to prototype LLM/agent flows instead? See **[Flowise](https://laradock.io/docs/services/flowise)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Ollama Source: https://laradock.io/docs/services/ollama ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Ollama? [Ollama](https://ollama.com) runs open LLMs locally and exposes an OpenAI-compatible HTTP API, giving PHP apps local inference with no external calls or per-token cost. Point [Prism](https://prism.echolabs.dev), [Neuron AI](https://github.com/inspector-apm/neuron-ai), [LLPhant](https://github.com/theodo-group/LLPhant), or [openai-php](https://github.com/openai-php/client) at it, and pair it with `pgvector` for fully local RAG. ## Start Ollama ```bash ./laradock start ollama ``` ```bash docker compose up -d ollama ``` ## Stop Ollama Stopping just pauses the container; downloaded models are safe (they live in the `ollama` Docker volume, not in the container itself): ```bash ./laradock stop ollama ``` ```bash docker compose stop ollama ``` To delete the container entirely (the `ollama` volume, and every model in it, is still untouched): ```bash ./laradock remove ollama ``` ```bash docker compose rm -sf ollama ``` ## Configuration All settings live in `ollama/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `OLLAMA_VERSION` | `latest` | Image tag from the [`ollama/ollama`](https://hub.docker.com/r/ollama/ollama) Docker Hub image. | | `OLLAMA_HOST_PORT` | `11434` | Host-side port Ollama is published on (container port `11434`). | Models are stored in the `ollama` named Docker volume at `/root/.ollama`, not under `DATA_PATH_HOST`, so they persist across container restarts but aren't visible directly on your host filesystem. ## Pull, list, and remove models No model is downloaded by default, pull one before your first request: ```bash ./laradock exec ollama ollama pull llama3.2 ``` ```bash docker compose exec ollama ollama pull llama3.2 ``` See everything you've already downloaded: ```bash ./laradock exec ollama ollama list ``` ```bash docker compose exec ollama ollama list ``` See which models are currently loaded into memory and answering requests: ```bash ./laradock exec ollama ollama ps ``` ```bash docker compose exec ollama ollama ps ``` Free up disk space by removing a model you no longer need: ```bash ./laradock exec ollama ollama rm llama3.2 ``` ```bash docker compose exec ollama ollama rm llama3.2 ``` ## Use the API The API is at `http://localhost:11434` from your host, or `http://ollama:11434` from other containers. It's OpenAI-compatible under `http://ollama:11434/v1`, so most OpenAI PHP SDKs work by just pointing the base URL there. ## Enable GPU acceleration Ollama's `compose.yml` runs CPU-only by default, no GPU is reserved for it. If your host has an NVIDIA GPU with the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) installed, add a device reservation to `ollama/compose.yml`: ```yaml services: ollama: deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] ``` Apply it with `./laradock rebuild ollama` and `./laradock restart ollama`. Without this, larger models fall back to CPU inference, which is noticeably slower. ## Start completely fresh (wipe all models) To throw away every downloaded model and start from a clean volume (this **permanently deletes** everything in the `ollama` volume): ```bash ./laradock stop ollama ./laradock remove ollama docker volume ls | grep ollama docker volume rm ./laradock start ollama ``` ```bash docker compose stop ollama docker compose rm -sf ollama docker volume ls | grep ollama docker volume rm docker compose up -d ollama ``` The volume name is prefixed with your project name (`COMPOSE_PROJECT_NAME`), so it's usually something like `_ollama`, `docker volume ls | grep ollama` shows the exact name on your machine. Removing individual models with `ollama rm` (above) is safer and usually all you need, only wipe the whole volume if you want a truly clean slate. ## Talk to Ollama from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Ollama by container name out of the box. Since the port is already published (`OLLAMA_HOST_PORT`), point the other project at your **host machine's** address instead of `ollama`, for example `http://host.docker.internal:11434` (Docker Desktop). Make sure the two projects use different `OLLAMA_HOST_PORT` values if they're both running at once, running one shared Ollama for multiple projects saves you from downloading the same multi-GB models twice. ## Common issues - **First request after starting is slow or fails.** No model is pulled by default, run `./laradock exec ollama ollama pull ` first; the pull itself can take a while depending on model size and your connection. - **Out of disk space.** Models are large (several GB each) and accumulate in the `ollama` volume. Remove unused ones with `./laradock exec ollama ollama rm `. - **CPU-only inference is slow.** Ollama uses GPU acceleration when available; see [Enable GPU acceleration](#enable-gpu-acceleration) above. - **App can't connect but the container is running.** Use the container name `ollama`, not `localhost`, from inside another container. --- Need a unified gateway across multiple LLM providers instead? See **[LiteLLM](https://laradock.io/docs/services/litellm)**. Need an OpenAI-compatible server with more model formats? See **[LocalAI](https://laradock.io/docs/services/localai)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Open WebUI Source: https://laradock.io/docs/services/open-webui ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Open WebUI? [Open WebUI](https://openwebui.com) is a ChatGPT-style web interface for local models. [Ollama](https://laradock.io/docs/services/ollama) gives you an API; Open WebUI gives you the chat window in front of it: pick a model, hold a conversation, upload a document to ask questions about, all in the browser with no cloud account and no per-token bill. ## Start Open WebUI Open WebUI is a front end, so it needs a model backend running behind it. By default that's Ollama: ```bash ./laradock start open-webui ollama ``` ```bash docker compose up -d open-webui ollama ``` Then open [http://localhost:8322](http://localhost:8322). On first visit you'll be asked to create an account. It's stored locally in the container's own volume, nothing is sent anywhere. ## Pull a model first A fresh Ollama has no models, so the model dropdown will be empty until you pull one: ```bash docker compose exec ollama ollama pull llama3.2 ``` Refresh Open WebUI and `llama3.2` appears in the model picker. See [Ollama](https://laradock.io/docs/services/ollama) for more on managing models. ## Stop Open WebUI ```bash ./laradock stop open-webui ``` ```bash docker compose stop open-webui ``` To remove the container: ```bash ./laradock remove open-webui ``` ```bash docker compose rm -sf open-webui ``` Your accounts, chat history, and settings live in the `open-webui` Docker volume, so removing the container keeps them: starting it again picks up where you left off. ## Configuration All settings live in `open-webui/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `OPEN_WEBUI_VERSION` | `main` | Image tag from [`ghcr.io/open-webui/open-webui`](https://github.com/open-webui/open-webui/pkgs/container/open-webui). | | `OPEN_WEBUI_PORT` | `8322` | Host-side port Open WebUI is published on (container port `8080`). | | `OPEN_WEBUI_LLM_ENGINE` | `ollama` | Which Laradock model service to talk to. | | `OPEN_WEBUI_LLM_PORT` | `11434` | Port that service listens on. | | `OPEN_WEBUI_AUTH` | `true` | `false` skips the login screen entirely. | ## Point it at LocalAI instead `OPEN_WEBUI_LLM_ENGINE` is the service name Open WebUI talks to, so it retargets without editing any compose file. To use [LocalAI](https://laradock.io/docs/services/localai) instead of Ollama, set both the engine and its port in your `.env`: ```env OPEN_WEBUI_LLM_ENGINE=localai OPEN_WEBUI_LLM_PORT=8080 ``` Then start the pair: ```bash ./laradock start open-webui localai ``` ```bash docker compose up -d open-webui localai ``` ## Skip the login screen Signing in on every fresh volume gets old on a dev machine. Setting `OPEN_WEBUI_AUTH=false` in your `.env` drops the account system entirely and opens straight into the chat: ```env OPEN_WEBUI_AUTH=false ``` Only do this when nothing else can reach the port. With auth off, anyone who can open `http://localhost:8322` gets full access, including any machine on your network if the port isn't firewalled. Decide before the first boot, because the switch sticks in both directions: once an account exists Open WebUI refuses to turn auth off, and once you've run without it, turning it back on locks you out of the account it created for you. Either way the way out is a fresh volume: ```bash docker volume rm laradock_open-webui ``` ## Change the Open WebUI version Set the version in your `.env`: ```env OPEN_WEBUI_VERSION=v0.5.20 ``` `open-webui` runs a pulled image, not a local build, so pull the new tag first: ```bash docker compose pull open-webui ``` Then recreate the container on it: ```bash ./laradock start open-webui ``` ```bash docker compose up -d open-webui ``` ## Common issues - **Model dropdown is empty.** Ollama has no models until you pull one: `docker compose exec ollama ollama pull llama3.2`. - **"Server connection failed".** The backend isn't running. Start it (`./laradock start ollama`) and confirm `OPEN_WEBUI_LLM_ENGINE` matches a real Laradock service name. - **Blank page or slow first load.** The image is large and the first boot builds its local database. Watch progress with `./laradock logs open-webui`. - **Replies are very slow.** The model runs on CPU unless a GPU is wired up, and larger models are slower. Try a smaller one (`llama3.2:1b`) or see [Ollama](https://laradock.io/docs/services/ollama) for GPU notes. - **Port 8322 already taken.** Change `OPEN_WEBUI_PORT` in your `.env`. --- Need the model engine itself? See **[Ollama](https://laradock.io/docs/services/ollama)** or **[LocalAI](https://laradock.io/docs/services/localai)**. Routing to cloud providers too? **[LiteLLM](https://laradock.io/docs/services/litellm)** puts one OpenAI-compatible endpoint in front of everything. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Qdrant Source: https://laradock.io/docs/services/qdrant ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Qdrant? [Qdrant](https://qdrant.tech) is a high-performance vector database for storing and querying embeddings, used for semantic search and RAG (retrieval-augmented generation) pipelines. It exposes both a REST API and a gRPC API, plus a built-in web dashboard. ## Start Qdrant ```bash ./laradock start qdrant ``` ```bash docker compose up -d qdrant ``` Your collections are created on first use and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start qdrant workspace`. ## Stop Qdrant Stopping just pauses the container; **your collections are safe**: ```bash ./laradock stop qdrant ``` ```bash docker compose stop qdrant ``` To delete the container entirely (the data in the `qdrant` volume is still untouched): ```bash ./laradock remove qdrant ``` ```bash docker compose rm -sf qdrant ``` ## Configuration All settings live in `qdrant/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `QDRANT_VERSION` | `latest` | Image tag from the [`qdrant/qdrant`](https://hub.docker.com/r/qdrant/qdrant) Docker Hub image. | | `QDRANT_HOST_PORT` | `6333` | Host-side port for the REST API (container port `6333`). | | `QDRANT_GRPC_PORT` | `6334` | Host-side port for the gRPC API (container port `6334`). | Collections persist in the `qdrant` named Docker volume, mounted at `/qdrant/storage` inside the container, across restarts. ## Connect REST API is at `http://localhost:6333`, health check `/healthz`, built-in dashboard at `/dashboard`. gRPC is on `6334`. From another container, use `http://qdrant:6333` (or `qdrant:6334` for gRPC). ## Check collection and cluster health Qdrant reports collection state through the REST API, useful after a bulk import or to confirm indexing finished: ```bash curl http://localhost:6333/collections/ ``` The `status` field is `green` (fully indexed and ready), `yellow` (indexing/optimizing in the background, still usable), or `red` (something failed). The response also includes `vectors_count` and `points_count` so you can confirm an import actually landed. To confirm the node itself is up before your app starts querying it: ```bash curl http://localhost:6333/healthz ``` ## Enable API key authentication By default this container accepts unauthenticated requests from anyone who can reach its port, fine for local development but worth locking down if you expose it beyond your own machine. Set an API key in your `.env`: ```env QDRANT__SERVICE__API_KEY=your-secret-key ``` Then apply it: ```bash ./laradock restart qdrant ``` ```bash docker compose restart qdrant ``` Every REST and gRPC request then needs an `api-key` header: ```bash curl -H "api-key: your-secret-key" http://localhost:6333/collections ``` Update your app's Qdrant client config with the same key, otherwise it starts getting `401 Unauthorized` responses after you turn this on. ## Backup and restore Qdrant backs up data per collection via its built-in snapshot API rather than a file you copy off disk directly. **Create a snapshot** of a collection: ```bash curl -X POST http://localhost:6333/collections//snapshots ``` **List existing snapshots** for a collection: ```bash curl http://localhost:6333/collections//snapshots ``` **Download a snapshot** to your host machine: ```bash curl -o backup.snapshot http://localhost:6333/collections//snapshots/ ``` **Restore** a collection from a snapshot file by uploading it back through the same API (see the [Qdrant snapshot docs](https://qdrant.tech/documentation/concepts/snapshots/) for the exact recovery endpoint and options for your Qdrant version, since this has changed across releases). Keep the `.snapshot` file itself somewhere safe, it's the actual backup. ## Start completely fresh (wipe all data) To throw away every collection and start Qdrant from a clean, empty state (⚠️ this **permanently deletes** everything in the `qdrant` volume, back up any collections you need first): ```bash ./laradock stop qdrant ./laradock remove qdrant docker volume rm "${COMPOSE_PROJECT_NAME}_qdrant" ./laradock start qdrant ``` ```bash docker compose stop qdrant docker compose rm -sf qdrant docker volume rm "${COMPOSE_PROJECT_NAME}_qdrant" docker compose up -d qdrant ``` Unlike bind-mounted services, Qdrant's storage lives in a **named Docker volume**, not a folder under `DATA_PATH_HOST`, so wiping it means removing the volume itself. If you're unsure of the exact volume name on your machine (it's prefixed with your `COMPOSE_PROJECT_NAME`), list it first with `docker volume ls | grep qdrant`. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Qdrant by container name out of the box. Easiest fix: the REST and gRPC ports are already published (`QDRANT_HOST_PORT`, `QDRANT_GRPC_PORT`), so point the other project at your **host machine's** address instead of `qdrant`, for example `http://host.docker.internal:6333` (Docker Desktop). Make sure the two projects use different `QDRANT_HOST_PORT`/`QDRANT_GRPC_PORT` values if they're both running at once. ## Common issues - **Dashboard shows no collections.** Collections are created via the API, not automatically. Create one first, either through the dashboard's "create collection" flow or a `PUT /collections/` call. - **gRPC client can't connect.** Confirm you're using port `6334`, not the REST port `6333`, gRPC and REST are separate ports on this image. - **Port already in use on your host.** Change `QDRANT_HOST_PORT` or `QDRANT_GRPC_PORT` in `.env` and restart: `./laradock restart qdrant`. - **App can't connect but the container is running.** Use the container name `qdrant`, not `localhost`, from inside another container. - **Requests suddenly return `401 Unauthorized`.** You (or a teammate) set `QDRANT__SERVICE__API_KEY`. Add the matching `api-key` header to every request, or unset the variable and restart if auth wasn't intended. --- Comparing vector databases? See **[Weaviate](https://laradock.io/docs/services/weaviate)** and **[Chroma](https://laradock.io/docs/services/chroma)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # vLLM Source: https://laradock.io/docs/services/vllm ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is vLLM? [vLLM](https://docs.vllm.ai) is a high-throughput inference server for open LLMs, exposing an OpenAI-compatible HTTP API. Like [Ollama](https://laradock.io/docs/services/ollama), it keeps inference local, no external calls, no per-token cost. Unlike Ollama, it's built for serving many concurrent requests efficiently, which is what you want once an LLM feature is in production rather than on your laptop. Point [Prism](https://prism.echolabs.dev), [Neuron AI](https://github.com/inspector-apm/neuron-ai), [LLPhant](https://github.com/theodo-group/LLPhant), or [openai-php](https://github.com/openai-php/client) at it, and pair it with `pgvector` for fully local RAG. ## Ollama or vLLM? They solve the same problem at different ends. Pick one: | | **Ollama** | **vLLM** | |---|---|---| | **Hardware** | CPU or GPU | **NVIDIA GPU required** | | **Models** | Pulled on demand, swap anytime | One model, chosen at startup | | **Best at** | Local development, trying models out | Serving concurrent traffic | | **Setup cost** | Start it, pull a model | Needs a GPU host and the NVIDIA Container Toolkit | If you're on a laptop, or you don't know which you want, use **Ollama**. Reach for vLLM when throughput on a real GPU is the point. ## Requirements vLLM has **no usable CPU path**, the container will not start without a GPU. You need: - An NVIDIA GPU with enough VRAM for your chosen model. - The [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) installed on the host. Verify Docker can see the GPU before you start: ```bash docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi ``` If that prints your GPU, you're ready. If it doesn't, fix that first, vLLM won't work until it does. ## Start vLLM Unlike Ollama, vLLM loads its model **at startup**, so the first boot downloads the model before the API answers. Watch the logs to know when it's ready. ```bash ./laradock start vllm ./laradock logs vllm ``` ```bash docker compose up -d vllm docker compose logs -f vllm ``` The default model (`Qwen/Qwen2.5-1.5B-Instruct`) is small and ungated, so it starts with no token and no extra configuration. ## Stop vLLM Stopping just pauses the container; downloaded model weights are safe (they live in the `vllm` Docker volume, not in the container itself): ```bash ./laradock stop vllm ``` ```bash docker compose stop vllm ``` To delete the container entirely (the `vllm` volume, and every weight in it, is still untouched): ```bash ./laradock remove vllm ``` ```bash docker compose rm -sf vllm ``` ## Configuration All settings live in `vllm/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `VLLM_VERSION` | `latest` | Image tag from the [`vllm/vllm-openai`](https://hub.docker.com/r/vllm/vllm-openai) Docker Hub image. | | `VLLM_HOST_PORT` | `8000` | Host-side port vLLM is published on (container port `8000`). | | `VLLM_MODEL` | `Qwen/Qwen2.5-1.5B-Instruct` | Hugging Face model loaded at startup. | | `VLLM_HUGGING_FACE_HUB_TOKEN` | *(empty)* | Required only for gated models (Llama, Gemma, ...). | | `VLLM_SHM_SIZE` | `8gb` | Shared memory for the container. Raise it for large or multi-GPU models. | Weights are cached in the `vllm` named Docker volume at `/root/.cache/huggingface`, not under `DATA_PATH_HOST`, so they persist across container restarts but aren't visible directly on your host filesystem. :::note Port 8000 is also FrankenPHP's default If you run `frankenphp` and `vllm` at the same time, change one of them, for example `VLLM_HOST_PORT=8001` in your `.env`. ::: ## Change the model vLLM serves **one model per container**, set at startup. To switch, change the setting and restart: ```bash ./laradock set VLLM_MODEL=mistralai/Mistral-7B-Instruct-v0.3 ./laradock restart vllm ``` ```bash # add VLLM_MODEL=mistralai/Mistral-7B-Instruct-v0.3 to your .env docker compose up -d --force-recreate vllm ``` For a **gated** model (most Llama and Gemma releases), accept the licence on its Hugging Face page, then set a [token](https://huggingface.co/settings/tokens): ```bash ./laradock set VLLM_HUGGING_FACE_HUB_TOKEN=hf_xxxxxxxxxxxx ./laradock restart vllm ``` ## Use the API The API is at `http://localhost:8000` from your host, or `http://vllm:8000` from other containers. It's OpenAI-compatible under `http://vllm:8000/v1`, so most OpenAI PHP SDKs work by just pointing the base URL there. Check it's up and see which model is loaded: ```bash curl http://localhost:8000/v1/models ``` The model name in your API calls must match `VLLM_MODEL` exactly, including the org prefix (`Qwen/Qwen2.5-1.5B-Instruct`, not `qwen`). ## Start completely fresh (wipe all weights) To throw away every downloaded model and start from a clean volume (this **permanently deletes** everything in the `vllm` volume): ```bash ./laradock stop vllm ./laradock remove vllm docker volume ls | grep vllm docker volume rm ./laradock start vllm ``` ```bash docker compose stop vllm docker compose rm -sf vllm docker volume ls | grep vllm docker volume rm docker compose up -d vllm ``` The volume name is prefixed with your project name (`COMPOSE_PROJECT_NAME`), so it's usually something like `_vllm`, `docker volume ls | grep vllm` shows the exact name on your machine. ## Common issues - **Container exits immediately.** Almost always no GPU visible to Docker. Run the `nvidia-smi` check in [Requirements](#requirements) above. - **First start takes a long time.** The model downloads before the API answers. Follow `./laradock logs vllm` and wait for the startup line; subsequent starts reuse the cached weights. - **`401` or "gated repo" in the logs.** The model needs a licence acceptance plus `VLLM_HUGGING_FACE_HUB_TOKEN`. See [Change the model](#change-the-model). - **Out of memory / CUDA OOM.** The model is too large for your VRAM. Use a smaller model or a quantised build. - **Port 8000 already in use.** FrankenPHP publishes the same port, set `VLLM_HOST_PORT=8001`. - **App can't connect but the container is running.** Use the container name `vllm`, not `localhost`, from inside another container. ## Run vLLM on a non-NVIDIA host The `deploy.resources` block in `vllm/compose.yml` reserves an NVIDIA device. For AMD ROCm, swap the image tag for a ROCm build and replace that block per the [vLLM installation docs](https://docs.vllm.ai/en/latest/getting_started/installation.html). On a machine with no GPU at all, use **[Ollama](https://laradock.io/docs/services/ollama)** instead, it's the CPU-friendly option. --- Want to pull models on demand, or don't have a GPU? See **[Ollama](https://laradock.io/docs/services/ollama)**. Need a unified gateway across multiple LLM providers? See **[LiteLLM](https://laradock.io/docs/services/litellm)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Weaviate Source: https://laradock.io/docs/services/weaviate ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Weaviate? [Weaviate](https://weaviate.io) is an open-source vector database with REST and GraphQL APIs, used for embeddings and RAG (retrieval-augmented generation) from PHP over plain HTTP. Unlike some vector databases, it ships GraphQL as a first-class query interface alongside REST. ## Start Weaviate ```bash ./laradock start weaviate ``` ```bash docker compose up -d weaviate ``` Your data is created on first start and kept between restarts, in a Docker volume (not a `DATA_PATH_HOST` bind mount). Name any other services alongside it to start them together, for example `./laradock start weaviate workspace`. ## Stop Weaviate Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop weaviate ``` ```bash docker compose stop weaviate ``` To delete the container entirely (the data on disk, in the `weaviate` volume, is still untouched): ```bash ./laradock remove weaviate ``` ```bash docker compose rm -sf weaviate ``` ## Configuration All settings live in `weaviate/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `WEAVIATE_VERSION` | `1.38.2` | Image tag from [`cr.weaviate.io/semitechnologies/weaviate`](https://weaviate.io/developers/weaviate). | | `WEAVIATE_HOST_PORT` | `8085` | Host-side port Weaviate is published on (container port `8080`). | `weaviate/compose.yml` also sets, directly in the container environment: `AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true` (no auth needed by default), `DEFAULT_VECTORIZER_MODULE=none` (you supply your own vectors/embeddings rather than Weaviate generating them), and `QUERY_DEFAULTS_LIMIT=25`. Data persists at `/var/lib/weaviate` in the `weaviate` volume. ## Change the Weaviate version Set the version in your `.env`: ```env WEAVIATE_VERSION=1.37.0 ``` Then apply it, this recreates the container and pulls the new image tag automatically: ```bash ./laradock start weaviate ``` ```bash docker compose up -d weaviate ``` ## Connect Reachable at `http://localhost:8085`, REST endpoints under `/v1`, GraphQL at `/v1/graphql`. Anonymous access is on by default, no API key needed for local dev. From another container, use `http://weaviate:8080`. ## Check status and version Weaviate's own health/meta endpoints, useful for confirming the cluster came up cleanly before your app starts querying it: ```bash curl http://localhost:8085/v1/.well-known/ready curl http://localhost:8085/v1/.well-known/live curl http://localhost:8085/v1/meta ``` `/v1/.well-known/ready` returns `200` once Weaviate can serve traffic (empty body); `/v1/meta` returns JSON with the running version and enabled modules, handy for confirming `WEAVIATE_VERSION` actually took effect after a version bump. ## Enable API key authentication `AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true` in `weaviate/compose.yml` means anyone who can reach the container can read and write data, fine for local dev, not for anything you'd expose beyond your own machine. To require an API key, edit the `environment:` block in `weaviate/compose.yml`: ```yaml - AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=false - AUTHENTICATION_APIKEY_ENABLED=true - AUTHENTICATION_APIKEY_ALLOWED_KEYS=your-secret-key - AUTHENTICATION_APIKEY_USERS=admin@example.com ``` Then apply it: ```bash ./laradock start weaviate ``` ```bash docker compose up -d weaviate ``` Clients then need `Authorization: Bearer your-secret-key` on every request. ## Backup and restore Weaviate's data lives in the `weaviate` Docker volume rather than a host path, so back it up by copying the volume's contents out of the running container: ```bash docker compose cp weaviate:/var/lib/weaviate ./weaviate-backup ``` To restore into a fresh container, stop it first so nothing is writing to disk mid-copy: ```bash ./laradock stop weaviate docker compose cp ./weaviate-backup/. weaviate:/var/lib/weaviate ./laradock start weaviate ``` There's no dedicated `./laradock` verb for copying files in and out of a container, `docker compose cp` is the same either way. ## Start completely fresh (wipe all data) To throw away every collection and object and start Weaviate from a clean, empty state (⚠️ this **permanently deletes** everything in this container, back up first if you need anything): ```bash ./laradock stop weaviate ./laradock remove weaviate docker volume rm $(docker volume ls -q --filter name=_weaviate$) ./laradock start weaviate ``` ```bash docker compose stop weaviate docker compose rm -sf weaviate docker volume rm $(docker volume ls -q --filter name=_weaviate$) docker compose up -d weaviate ``` The volume is named `_weaviate` (the `` prefix is your `COMPOSE_PROJECT_NAME`), the filter above matches it regardless of what your project is named. Deleting it and starting again is equivalent to a brand-new install: no collections, no objects. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Weaviate by container name out of the box. Easiest fix: publish the port (already done, `WEAVIATE_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `weaviate`, for example `http://host.docker.internal:8085` (Docker Desktop). Make sure the two projects use different `WEAVIATE_HOST_PORT` values if they're both running at once. ## Common issues - **Objects rejected for missing a vector.** `DEFAULT_VECTORIZER_MODULE=none` means Weaviate expects you to provide vectors yourself (e.g. from OpenAI, Ollama, or your own embedding model); it won't generate them for you unless you enable and configure a vectorizer module. - **Query returns fewer results than expected.** `QUERY_DEFAULTS_LIMIT=25` caps default query results; pass an explicit `limit` in your query if you need more. - **Port already in use on your host.** Change `WEAVIATE_HOST_PORT` in `.env` and restart: `./laradock restart weaviate`. - **App can't connect but the container is running.** Use the container name `weaviate` on port `8080`, not `localhost`, from inside another container. - **Anyone can read or write your data.** Anonymous access is on by default (see [Enable API key authentication](#enable-api-key-authentication) above), fine for local dev, not for anything reachable beyond your own machine. --- Comparing vector databases? See **[Qdrant](https://laradock.io/docs/services/qdrant)** and **[Chroma](https://laradock.io/docs/services/chroma)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Aerospike Source: https://laradock.io/docs/services/aerospike ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Aerospike? [Aerospike](https://aerospike.com) is a distributed, high-performance NoSQL key-value database built for low-latency reads and writes at scale, commonly used for real-time use cases like ad targeting, fraud detection, and session stores. ## Start Aerospike ```bash ./laradock start aerospike ``` ```bash docker compose up -d aerospike ``` Your data is created on first start and kept between restarts. ## Stop Aerospike Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop aerospike ``` ```bash docker compose stop aerospike ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove aerospike ``` ```bash docker compose rm -sf aerospike ``` ## Configuration All settings live in `aerospike/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `AEROSPIKE_SERVICE_PORT` | `3000` | Host-side port for the client service port. | | `AEROSPIKE_FABRIC_PORT` | `3001` | Host-side port for inter-node cluster communication. | | `AEROSPIKE_HEARTBEAT_PORT` | `3002` | Host-side port for cluster heartbeat messages. | | `AEROSPIKE_INFO_PORT` | `3003` | Host-side port for the info/monitoring protocol. | | `AEROSPIKE_STORAGE_GB` | `1` | Storage size (in GB) allocated to the container, passed in as `STORAGE_GB`. | | `AEROSPIKE_MEM_GB` | `1` | Memory limit (in GB) for the container, passed in as `MEM_GB`. | | `AEROSPIKE_NAMESPACE` | `test` | Default Aerospike namespace created on boot, passed in as `NAMESPACE`. | ## Change namespace, storage, or memory limits `AEROSPIKE_NAMESPACE`, `AEROSPIKE_STORAGE_GB`, and `AEROSPIKE_MEM_GB` are passed into the container as plain runtime environment variables (not baked in at build time), so a restart is enough to apply a change, no rebuild needed. Set the new value in `.env`, then: ```bash ./laradock restart aerospike ``` ```bash docker compose restart aerospike ``` Changing `AEROSPIKE_NAMESPACE` doesn't rename or migrate data already stored under the old namespace, it just changes which namespace the server exposes on boot. ## Change the Aerospike version The version is pinned by the `AEROSPIKE_VERSION` build arg at the top of `aerospike/Dockerfile` (`ce-8.1.2.2` by default), it isn't exposed as an `.env` variable. Edit that line to the tag you want from [Aerospike's Docker Hub](https://hub.docker.com/r/aerospike/aerospike-server), then rebuild: ```bash ./laradock rebuild aerospike ``` ```bash docker compose build aerospike ``` ## Connect from PHP Aerospike needs its own PHP extension to talk to the server from `php-fpm`/`workspace`. That's a separate install step, see **[Install the Aerospike extension](https://laradock.io/docs/services/php-fpm#install-the-aerospike-extension)** for the `WORKSPACE_INSTALL_AEROSPIKE`/`PHP_FPM_INSTALL_AEROSPIKE` flags and rebuild command. Once installed, connect to the server by container name and service port: ```php $client = new Aerospike(["hosts" => [["addr" => "aerospike", "port" => 3000]]]); ``` ## Connect from your host machine Inside Laradock, other containers reach it by container name: `aerospike:3000`. From your own machine, connect to `localhost:3000` (or your custom `AEROSPIKE_SERVICE_PORT`) using the Aerospike CLI tools or a compatible client. ## Check node status Open a terminal inside the container, then ask the running node for its status: ```bash ./laradock enter aerospike asinfo -v status ``` ```bash docker compose exec aerospike bash asinfo -v status ``` A healthy node replies `ok`. Run `asinfo -v namespaces` the same way to list the namespaces currently configured on the node. ## Backup and restore Aerospike's data lives entirely under the `DATA_PATH_HOST/aerospike` volume mount, so backing it up is a matter of stopping the node and copying that folder while nothing is writing to it. **Back up:** ```bash ./laradock stop aerospike ``` ```bash docker compose stop aerospike ``` ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/aerospike" ./aerospike-backup-$(date +%Y%m%d) ``` ```bash ./laradock start aerospike ``` ```bash docker compose up -d aerospike ``` **Restore** from a backup folder made the same way (⚠️ this replaces everything currently in `DATA_PATH_HOST/aerospike`): ```bash ./laradock stop aerospike ``` ```bash docker compose stop aerospike ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/aerospike" cp -r ./aerospike-backup-20260101 "${DATA_PATH_HOST:-~/.laradock/data}/aerospike" ``` ```bash ./laradock start aerospike ``` ```bash docker compose up -d aerospike ``` ## Start completely fresh (wipe all data) To throw away everything and start Aerospike from a clean, empty state (⚠️ this **permanently deletes** all data in this container, back up first if you need anything): ```bash ./laradock stop aerospike ./laradock remove aerospike rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/aerospike" ./laradock start aerospike ``` ```bash docker compose stop aerospike docker compose rm -sf aerospike rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/aerospike" docker compose up -d aerospike ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Aerospike's data actually lives on your machine. ## Talk to this from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Aerospike by container name out of the box. Easiest fix: the service, fabric, heartbeat, and info ports are already published to your host, so have the other project connect to your **host machine's** address instead of `aerospike`, for example `host.docker.internal` (Docker Desktop) with the port set to this project's `AEROSPIKE_SERVICE_PORT`. Make sure the two projects use different values for all four Aerospike ports if they're both running at once. ## Common issues - **Client can't connect at all.** Aerospike needs all four ports (service, fabric, heartbeat, info) reachable for the node to run correctly, not just the service port. Confirm none of `AEROSPIKE_SERVICE_PORT`/`AEROSPIKE_FABRIC_PORT`/`AEROSPIKE_HEARTBEAT_PORT`/`AEROSPIKE_INFO_PORT` collide with something else on your host. - **"Namespace not found" errors.** Your client is targeting a namespace that doesn't match `AEROSPIKE_NAMESPACE` (default `test`). Either use that namespace or change `AEROSPIKE_NAMESPACE` and `./laradock restart aerospike`. - **PHP calls fail with "class Aerospike not found."** The PHP extension isn't installed yet, it's not bundled by default. Follow **[Install the Aerospike extension](https://laradock.io/docs/services/php-fpm#install-the-aerospike-extension)** and rebuild `workspace`/`php-fpm`. - **Out-of-memory or storage errors under real load.** `AEROSPIKE_MEM_GB`/`AEROSPIKE_STORAGE_GB` default to `1`, fine for local dev, but bump them in `.env` if you're testing with meaningful data volumes, then `./laradock restart aerospike`. - **Node reports itself unhealthy after a host reboot.** Run `./laradock logs aerospike` and check for storage errors before assuming data is lost, a node re-joining after an unclean shutdown can take a few seconds to come back to `ok` in `asinfo -v status`. --- New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Beanstalkd Console Source: https://laradock.io/docs/services/beanstalkd-console ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Beanstalkd Console? [Beanstalk Console](https://github.com/ptrofimov/beanstalk_console) is a small PHP web UI for inspecting a running Beanstalkd server: tubes, queued/reserved/buried jobs, and worker connections. Laradock builds it from source and serves it with PHP's built-in server. It's a companion to the `beanstalkd` service, not a queue server itself. ## Start Beanstalkd Console ```bash ./laradock start beanstalkd-console ``` ```bash docker compose up -d beanstalkd-console ``` The container `depends_on` the `beanstalkd` service in `compose.yml` (which in turn `depends_on` `php-fpm`), so Compose starts both automatically. A single command brings up the whole chain. ## Stop Beanstalkd Console ```bash ./laradock stop beanstalkd-console ``` ```bash docker compose stop beanstalkd-console ``` It holds no data of its own (it only reads from `beanstalkd`), so there's nothing to lose. To delete the container entirely: ```bash ./laradock remove beanstalkd-console ``` ```bash docker compose rm -sf beanstalkd-console ``` ## Configuration All settings live in `beanstalkd-console/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `BEANSTALKD_CONSOLE_HOST_PORT` | `2080` | Host-side port the console UI is published on (`host:2080`). | ## Connect the console to Beanstalkd 1. Make sure the `beanstalkd` service is running (Compose starts it automatically via `depends_on`, but it needs to be reachable). 2. Open [http://localhost:2080](http://localhost:2080) (or your custom `BEANSTALKD_CONSOLE_HOST_PORT`). 3. Add a server in the UI with host `beanstalkd` and port `11300`, the container name and internal port Beanstalkd listens on inside the Laradock network. The console doesn't auto-discover Beanstalkd on modern Docker networks, so this manual step is required every time you start from a fresh container (the added server isn't persisted anywhere on disk). ## Update the console The Dockerfile pulls the `master` branch of [`ptrofimov/beanstalk_console`](https://github.com/ptrofimov/beanstalk_console) fresh at build time rather than pinning a version. To pick up upstream fixes/changes, rebuild with no cache: ```bash ./laradock rebuild beanstalkd-console ``` ```bash docker compose build --no-cache beanstalkd-console ``` `--no-cache` matters here: without it, Docker may reuse a cached layer from the last time the source was fetched instead of downloading the current `master`. ## View logs Useful when the page won't load or shows a blank screen: ```bash ./laradock logs beanstalkd-console ``` ```bash docker compose logs --tail=100 beanstalkd-console ``` ## Common issues - **No server configured on first load.** The console doesn't auto-discover Beanstalkd; add the server manually (host `beanstalkd`, port `11300`) as described above. - **Can't reach `beanstalkd` from the console.** Both containers must be on the same Compose network (they are, by default, on `backend`) and `beanstalkd` must actually be running: `docker compose ps beanstalkd`. - **Port already in use on your host.** Another service is bound to `2080`. Change `BEANSTALKD_CONSOLE_HOST_PORT` in `.env` and restart: `./laradock restart beanstalkd-console`. - **Blank page or 502 after starting.** The container needs `beanstalkd` up first; if you started `beanstalkd-console` alone before Compose finished bringing up `beanstalkd`, give it a few seconds and refresh. --- Need the queue server itself? See **[Beanstalkd](https://laradock.io/docs/services/beanstalkd)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Beanstalkd Source: https://laradock.io/docs/services/beanstalkd ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Beanstalkd? [Beanstalkd](https://beanstalkd.github.io) is a simple, fast work-queue service, a lightweight alternative to Redis or Kafka when all you need is a job queue. Laravel supports it as a first-class queue driver. ## Start Beanstalkd ```bash ./laradock start beanstalkd ``` ```bash docker compose up -d beanstalkd ``` The container's `compose.yml` declares `depends_on: php-fpm`, so starting `beanstalkd` also starts `php-fpm` if it isn't running yet. ## Stop Beanstalkd ```bash ./laradock stop beanstalkd ``` ```bash docker compose stop beanstalkd ``` To delete the container entirely: ```bash ./laradock remove beanstalkd ``` ```bash docker compose rm -sf beanstalkd ``` Unlike a database service, `beanstalkd`'s `compose.yml` mounts no data volume, so this isn't a "your data is safe" situation: any queued/reserved/buried jobs still sitting in the queue are gone as soon as the container is removed. See [Job data isn't persisted](#job-data-isnt-persisted) below. ## Configuration All settings live in `beanstalkd/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `BEANSTALKD_HOST_PORT` | `11300` | Host-side port Beanstalkd is published on (`host:container`), Beanstalkd's standard port. | The container also runs `privileged: true` (set in `compose.yml`, not `.env`-configurable). ## Job data isn't persisted Laradock's `beanstalkd` image runs the daemon with no `-b` binlog flag and no volume mount, so it holds everything **in memory only**. This means: - Restarting the container (`./laradock restart beanstalkd`) keeps jobs, the process inside the container isn't replaced. - Removing the container (`./laradock remove beanstalkd`), rebuilding it, or restarting Docker itself **loses every queued, reserved, and buried job** with no way to recover them. If you need jobs to survive a container recreation, don't rely on Beanstalkd for anything that isn't safe to lose. There's nothing to back up here, unlike a database. ## Use Beanstalkd from Laravel 1. In `config/queue.php`, set `beanstalkd` as the default driver and `QUEUE_HOST=beanstalkd` (the container name). It listens on port `11300`. 2. Install the client: ```bash composer require pda/pheanstalk ``` ## Check queue stats from the CLI Beanstalkd speaks a simple text protocol, so you can query global stats without any client library by talking to the published port directly from your host machine: ```bash printf "stats\r\n" | nc localhost 11300 ``` This returns a YAML block with counters like `current-jobs-ready`, `current-jobs-reserved`, `current-connections`, and `total-jobs`. Swap `stats` for `list-tubes` to see which tubes currently exist. For anything beyond a quick check, the web console below is easier to read. ## Manage jobs from a web console Laradock also ships a `beanstalkd-console` container for browsing tubes and jobs visually: ```bash ./laradock start beanstalkd-console ``` ```bash docker compose up -d beanstalkd-console ``` Open [http://localhost:2080](http://localhost:2080) (change the port with `BEANSTALKD_CONSOLE_HOST_PORT`), then add a server with host `beanstalkd` and port `11300`. Full setup, update, and troubleshooting details live on the **[Beanstalkd Console](https://laradock.io/docs/services/beanstalkd-console)** page. ## Connect from your host machine Inside Laradock, other containers reach it by container name: `beanstalkd:11300`. From your own machine, connect to `localhost:11300` (or your custom `BEANSTALKD_HOST_PORT`). ## Common issues - **Queue worker can't connect but the container is running.** Confirm `QUEUE_HOST=beanstalkd` (the container name) in your app's `.env`, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Jobs pile up and never process.** Beanstalkd only stores jobs, something still has to run `php artisan queue:work`. Check the queue worker is actually running against the `beanstalkd` connection. - **Jobs vanished after a rebuild or `remove`.** Expected, see [Job data isn't persisted](#job-data-isnt-persisted). There's no volume to recover from. - **Port already in use on your host.** Another local Beanstalkd (or another Laradock project) is already bound to `11300`. Change `BEANSTALKD_HOST_PORT` in `.env` and restart: `./laradock restart beanstalkd`. - **Console shows no tubes/jobs.** Confirm the console's server entry uses host `beanstalkd` and port `11300` (the container-internal port), not the host-mapped `BEANSTALKD_HOST_PORT`. --- New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Dragonfly Source: https://laradock.io/docs/services/dragonfly ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Dragonfly? [Dragonfly](https://www.dragonflydb.io) is a modern, multi-threaded in-memory data store built as a drop-in replacement for Redis and Memcached, wire-compatible with both protocols but designed to make better use of multi-core machines for higher throughput. ## Start Dragonfly ```bash ./laradock start dragonfly ``` ```bash docker compose up -d dragonfly ``` Name any other services alongside it to start them together, for example `./laradock start dragonfly workspace`. ## Stop Dragonfly Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop dragonfly ``` ```bash docker compose stop dragonfly ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove dragonfly ``` ```bash docker compose rm -sf dragonfly ``` ## Configuration All settings live in `dragonfly/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `DRAGONFLY_VERSION` | `latest` | Image tag from [Dragonfly's registry](https://hub.docker.com/r/dragonflydb/dragonfly). | | `DRAGONFLY_PORT` | `6381` | Host-side port Dragonfly is published on (`host:container`). Deliberately not `6379`, so it can run alongside `redis`/`valkey`. | The container also sets `ulimits.memlock: -1`, Dragonfly needs unlimited locked memory to run correctly; this is fixed in `dragonfly/compose.yml` and isn't user-configurable via `.env`. ## Use Dragonfly from Laravel Point any Redis client at it the same way you would Redis. In your Laravel `.env`: ```env REDIS_HOST=dragonfly REDIS_PORT=6379 ``` Note the app-side `REDIS_PORT` here is the container-internal port (`6379`), not `DRAGONFLY_PORT`, containers talk to each other over the internal network, not the host-published port. ## Connect with the CLI client Dragonfly speaks the Redis protocol, so `redis-cli` (bundled in the image) works against it directly: ```bash ./laradock enter dragonfly redis-cli ``` ```bash docker compose exec dragonfly bash redis-cli ``` From your host machine instead, point any Redis GUI (RedisInsight, TablePlus) or the `redis-cli` binary at `localhost:6381` (or your custom `DRAGONFLY_PORT`). ## Check memory usage and stats From inside `redis-cli`: ```bash INFO memory DBSIZE MEMORY USAGE ``` `INFO memory` reports overall memory consumption, `DBSIZE` counts how many keys are stored, and `MEMORY USAGE ` sizes a single key, all standard Redis commands Dragonfly implements natively. ## Flush all data To wipe every key without stopping the container (⚠️ this **permanently deletes** everything in the current database, there is no undo): ```bash FLUSHALL ``` Run it from inside `redis-cli` (see [Connect with the CLI client](#connect-with-the-cli-client) above), or non-interactively: ```bash ./laradock exec dragonfly redis-cli FLUSHALL ``` ```bash docker compose exec dragonfly redis-cli FLUSHALL ``` ## Start completely fresh (wipe all data on disk) `FLUSHALL` clears keys in a running instance; to also remove the container and its on-disk snapshot and start from a totally clean state: ```bash ./laradock stop dragonfly ./laradock remove dragonfly rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/dragonfly" ./laradock start dragonfly ``` ```bash docker compose stop dragonfly docker compose rm -sf dragonfly rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/dragonfly" docker compose up -d dragonfly ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Dragonfly's data actually lives on your machine (mounted to `/data` in the container). ## Connect from your host machine Inside Laradock, other containers reach it by container name: `dragonfly:6379`. From your own machine, connect to `localhost:6381` (or your custom `DRAGONFLY_PORT`) with any Redis-compatible GUI like TablePlus or RedisInsight. ## Common issues - **App can't connect but the container is running.** Confirm the app's config uses `dragonfly` (the container name) as the host, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Confusing `DRAGONFLY_PORT` with the internal port.** `DRAGONFLY_PORT` (default `6381`) is only the host-side mapping. From inside another container, Dragonfly is always reachable on port `6379`. - **Container fails to start with a memlock-related error.** Some Docker setups (notably rootless or certain CI runners) restrict `ulimits.memlock`; you may need to adjust your Docker daemon/host configuration since this isn't controlled from Laradock's `.env`. - **Port already in use on your host.** Another local Dragonfly (or another Laradock project) is already bound to `6381`. Change `DRAGONFLY_PORT` in `.env` and restart: `./laradock restart dragonfly`. - **Memory keeps growing.** Dragonfly (like Redis) keeps everything in RAM. Check usage with `INFO memory`, and consider `FLUSHALL` or a fresh start above if a dev/test workload has filled it up with stale keys. --- Prefer upstream Redis instead? See **[Redis](https://laradock.io/docs/services/redis)**. Want the community Redis fork? See **[Valkey](https://laradock.io/docs/services/valkey)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Gearman Source: https://laradock.io/docs/services/gearman ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Gearman? [Gearman](http://gearman.org) is a job/task distribution system: applications submit units of work to a Gearman job server, which farms them out to registered workers. It's an older, language-agnostic alternative to Laravel's queue drivers, still common in polyglot or legacy PHP stacks. Laradock builds it from the `artefactual/gearmand` image. ## Start Gearman ```bash ./laradock start gearman ``` ```bash docker compose up -d gearman ``` The container `depends_on` `php-fpm` in `compose.yml`, so Compose starts `php-fpm` first automatically. ## Stop Gearman Stopping just pauses the container: ```bash ./laradock stop gearman ``` ```bash docker compose stop gearman ``` To remove the container entirely: ```bash ./laradock remove gearman ``` ```bash docker compose rm -sf gearman ``` Gearman itself keeps no data on disk (no volume is mounted for it in `compose.yml`): with the default in-memory queue, removing or recreating the container simply drops whatever was still queued. If you've switched to the MySQL-backed queue (see below), the jobs live in MySQL instead and survive the Gearman container being removed. ## Configuration All settings live in `gearman/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `GEARMAN_VERSION` | `latest` | Image tag from [artefactual/gearmand](https://hub.docker.com/r/artefactual/gearmand) on Docker Hub. | | `GEARMAN_PORT` | `4730` | Host-side port Gearman is published on (`host:4730`). | | `GEARMAN_VERBOSE` | `INFO` | Logging level. | | `GEARMAN_QUEUE_TYPE` | `builtin` | Persistent queue backend: `builtin` (in-memory) or `mysql`. | | `GEARMAN_THREADS` | `4` | Number of I/O threads. | | `GEARMAN_BACKLOG` | `32` | Listen backlog size for incoming connections. | | `GEARMAN_FILE_DESCRIPTORS` | *(empty)* | Max file descriptors for the process; empty uses the user's max. | | `GEARMAN_JOB_RETRIES` | `0` | Attempts before the server drops a job; `0` means no limit. | | `GEARMAN_ROUND_ROBIN` | `0` | Assign work round-robin across worker connections. | | `GEARMAN_WORKER_WAKEUP` | `0` | Number of workers woken per received job. | | `GEARMAN_KEEPALIVE` | `0` | Enable TCP keepalive on sockets. | | `GEARMAN_KEEPALIVE_IDLE` | `30` | Seconds idle before sending keepalive probes. | | `GEARMAN_KEEPALIVE_INTERVAL` | `10` | Seconds between keepalive retransmissions. | | `GEARMAN_KEEPALIVE_COUNT` | `5` | Retransmissions before declaring the peer unreachable. | | `GEARMAN_MYSQL_HOST` | `localhost` | MySQL host, used only when `GEARMAN_QUEUE_TYPE=mysql`. | | `GEARMAN_MYSQL_PORT` | `3306` | MySQL port for persistent queue storage. | | `GEARMAN_MYSQL_USER` | `root` | MySQL user for persistent queue storage. | | `GEARMAN_MYSQL_PASSWORD` | *(empty)* | MySQL password for persistent queue storage. | | `GEARMAN_MYSQL_PASSWORD_FILE` | *(empty)* | Path to a file holding the MySQL password (Docker secrets). | | `GEARMAN_MYSQL_DB` | `Gearmand` | Database used for the MySQL-backed persistent queue. | | `GEARMAN_MYSQL_TABLE` | `gearman_queue` | Table used for the MySQL-backed persistent queue. | ## Change the Gearman version Set the version in your `.env`: ```env GEARMAN_VERSION=1.1.19.4 ``` Then apply the change: ```bash ./laradock rebuild gearman ``` ```bash docker compose build gearman ``` Since Gearman keeps no data of its own on disk, there's no data-format compatibility to worry about across versions, just rebuild and restart. ## Persist the queue in MySQL By default Gearman keeps queued jobs in memory only (`GEARMAN_QUEUE_TYPE=builtin`), so they're lost on restart. To persist them, point Gearman at your **[MySQL](https://laradock.io/docs/services/mysql)** container: ```env GEARMAN_QUEUE_TYPE=mysql GEARMAN_MYSQL_HOST=mysql GEARMAN_MYSQL_USER=default GEARMAN_MYSQL_PASSWORD=secret GEARMAN_MYSQL_DB=default ``` Then apply the change: ```bash ./laradock start gearman ``` ```bash docker compose up -d gearman ``` Gearman doesn't create the target database or table for you, `GEARMAN_MYSQL_DB` (`default` above) must already exist and be reachable from the Gearman container before you switch `GEARMAN_QUEUE_TYPE` to `mysql`. ## Check queue status and connected workers Gearman exposes a plain-text admin protocol on the same port as the job protocol (`GEARMAN_PORT`, `4730` by default). From your host machine, with `nc` (netcat) installed: ```bash echo "status" | nc localhost 4730 ``` This lists every registered function with its total jobs queued, jobs running, and connected worker count, one per line, terminated by a line containing only `.`. To see the connected workers themselves instead: ```bash echo "workers" | nc localhost 4730 ``` Useful when jobs seem stuck: an empty `workers` list, or a function in `status` with queued jobs but no workers, means nothing is registered to actually process that function name. ## Connect from your app Inside Laradock, other containers reach Gearman by container name: host `gearman`, port `4730`. Use a Gearman PHP client library (such as the `gearman` PECL extension or a Composer package) to submit and process jobs. ## Talk to Gearman from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Gearman by container name out of the box. Easiest fix: publish the port (already done, `GEARMAN_PORT`) and have the other project's workers/clients connect to your **host machine's** address instead of `gearman`, for example `host.docker.internal` (Docker Desktop) on this project's `GEARMAN_PORT`. Make sure the two projects use different `GEARMAN_PORT` values if they're both running at once. ## Common issues - **Jobs disappear after a restart.** The default `builtin` queue type is in-memory only; switch to `GEARMAN_QUEUE_TYPE=mysql` if you need jobs to survive a container restart. - **`GEARMAN_QUEUE_TYPE=mysql` but jobs still aren't persisted.** Confirm the `GEARMAN_MYSQL_*` variables point at a reachable MySQL container and that the target database/table exist; Gearman doesn't create the database for you. - **Jobs are queued but never processed.** Check `status` and `workers` on the admin port (see [Check queue status and connected workers](#check-queue-status-and-connected-workers) above): if no worker is registered for a function, nothing will ever pick its jobs up. - **Port already in use on your host.** Another local Gearman (or another Laradock project) is already bound to `4730`. Change `GEARMAN_PORT` in `.env` and restart: `./laradock restart gearman`. - **App can't connect but the container is running.** Confirm your app connects to host `gearman` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. --- Need a Redis-backed alternative for Laravel queues? See **[Redis](https://laradock.io/docs/services/redis)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Kafka Manager Source: https://laradock.io/docs/services/kafka-manager ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Kafka Manager? Kafka Manager is a web-based tool for managing and monitoring Apache Kafka clusters: view brokers, topics, partitions, and consumer group offsets from a browser instead of the Kafka CLI tools. ## Start Kafka Manager ```bash ./laradock start zookeeper kafka kafka-manager ``` ```bash docker compose up -d zookeeper kafka kafka-manager ``` Kafka Manager talks to ZooKeeper to discover the cluster, so both `zookeeper` and `kafka` need to be running for it to be useful. ## Stop Kafka Manager ```bash ./laradock stop kafka-manager ``` ```bash docker compose stop kafka-manager ``` To delete the container entirely: ```bash ./laradock remove kafka-manager ``` ```bash docker compose rm -sf kafka-manager ``` ## Configuration `kafka-manager/defaults.env` doesn't exist, the container has no configurable `.env` variables. Its settings are fixed directly in `kafka-manager/compose.yml`: | Setting | Value | What it does | |---|---|---| | Host port | `9020` | Fixed mapping to the container's port `9000` (not overridable via `.env`). | | `ZK_HOSTS` | `zookeeper:2181` | ZooKeeper connection string the manager uses to discover the cluster. | ## Add your cluster 1. Open [http://localhost:9020](http://localhost:9020). 2. Add a cluster pointing at the ZooKeeper host `zookeeper:2181`. There's no login screen, no built-in authentication, anyone who can reach port `9020` can add/remove clusters and browse topic data. Fine for local development, but don't expose this port beyond your own machine. ## Where cluster config is stored Kafka Manager itself is stateless, it has no data volume of its own (check `kafka-manager/compose.yml`, there's no `volumes:` entry). Every cluster you add through the UI is actually persisted inside **ZooKeeper**, under its own znode, not inside the Kafka Manager container. That means: - Removing/recreating the `kafka-manager` container is safe, your added clusters survive. - Wiping ZooKeeper's data (`${DATA_PATH_HOST}/zookeeper`) removes the cluster list too, you'll need to re-add it via the UI afterward. ## Common issues - **Port `9020` already in use on your host.** Since it's hardcoded in `compose.yml` (not an `.env` variable), you'll need to edit `kafka-manager/compose.yml` directly to change it, or stop whatever else is bound to that port. - **"No clusters" or connection errors when adding a cluster.** Confirm `zookeeper` is actually running (`./laradock logs zookeeper`) before adding the cluster, and that you used `zookeeper:2181`, not `kafka:9092`, as the connection string. - **Topics/brokers don't show up.** Confirm `kafka` itself is up and has successfully registered with ZooKeeper; check `./laradock logs kafka` for startup errors. - **Cluster disappeared after a rebuild.** You likely wiped ZooKeeper's data folder rather than Kafka Manager's, see [Where cluster config is stored](#where-cluster-config-is-stored) above; re-add the cluster once ZooKeeper is back up. --- Need the Kafka broker itself? See **[Apache Kafka](https://laradock.io/docs/services/kafka)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Apache Kafka Source: https://laradock.io/docs/services/kafka ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Apache Kafka? [Apache Kafka](https://kafka.apache.org) is a distributed event-streaming platform for high-throughput publish/subscribe messaging, used for event pipelines, log aggregation, and decoupling services. Laradock's Kafka needs the `zookeeper` container running alongside it to manage broker coordination, that pairing is intrinsic to how Kafka works, not an arbitrary example. ## Start Kafka ```bash ./laradock start zookeeper kafka ``` ```bash docker compose up -d zookeeper kafka ``` ZooKeeper must be up before Kafka can register itself, always start (or restart) both together. ## Stop Kafka Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop kafka ``` ```bash docker compose stop kafka ``` To also stop ZooKeeper: ```bash ./laradock stop kafka zookeeper ``` ```bash docker compose stop kafka zookeeper ``` To delete the containers entirely (the data on disk is still untouched): ```bash ./laradock remove kafka zookeeper ``` ```bash docker compose rm -sf kafka zookeeper ``` ## Configuration `kafka/defaults.env` is empty, all Kafka configuration is fixed directly in `kafka/compose.yml` rather than exposed as `.env` overrides: | Setting | Value | What it does | |---|---|---| | `KAFKA_BROKER_ID` | `1` | Unique ID for this broker in the cluster. | | `KAFKA_ADVERTISED_HOST_NAME` | `127.0.0.1` | Hostname advertised to clients for connecting back. | | `KAFKA_ADVERTISED_LISTENERS` | `PLAINTEXT://127.0.0.1:9092` | Listener address advertised to clients. | | `KAFKA_MESSAGE_MAX_BYTES` | `2000000` | Maximum message size the broker accepts. | | `KAFKA_ZOOKEEPER_CONNECT` | `zookeeper:2181` | ZooKeeper connection string. | The broker listens on port `9092` (mapped `host:container` in `compose.yml`, not driven by an env var). Kafka data is stored under `DATA_PATH_HOST/kafka`, and the container also mounts `/var/run/docker.sock`. ZooKeeper itself is configured through `zookeeper/defaults.env`: | Variable | Default | What it does | |---|---|---| | `ZOOKEEPER_PORT` | `2181` | Host-side port ZooKeeper is published on. | Its own state lives under `DATA_PATH_HOST/zookeeper/data` and `DATA_PATH_HOST/zookeeper/datalog`. Editing anything in `kafka/compose.yml` or `zookeeper/defaults.env` requires a rebuild to take effect: ```bash ./laradock rebuild kafka zookeeper ``` ```bash docker compose build kafka zookeeper ``` ## Manage Kafka from a web UI Start Kafka Manager alongside it: ```bash ./laradock start kafka-manager ``` ```bash docker compose up -d kafka-manager ``` Open [http://localhost:9020](http://localhost:9020) and add a cluster pointing at the ZooKeeper host `zookeeper:2181`. See **[Kafka Manager](https://laradock.io/docs/services/kafka-manager)** for details. ## Working with topics The image ships Kafka's own CLI scripts inside the container under `/opt/kafka/bin`. Open a terminal in the container first: ```bash ./laradock enter kafka ``` ```bash docker compose exec kafka bash ``` Then, from inside the container: **List existing topics:** ```bash kafka-topics.sh --list --zookeeper zookeeper:2181 ``` **Create a topic:** ```bash kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 1 --topic my-topic ``` **Describe a topic** (partitions, replicas, leader): ```bash kafka-topics.sh --describe --zookeeper zookeeper:2181 --topic my-topic ``` ## Produce and consume messages from the CLI Handy for a quick sanity check without wiring up a real client. Run these from inside the container (`./laradock enter kafka`): **Produce** (type messages, one per line, `Ctrl+C` to stop): ```bash kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic ``` **Consume** (in a second terminal, also inside the container, prints new messages as they arrive): ```bash kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic ``` Add `--from-beginning` to the consumer command to replay everything already on the topic instead of only new messages. ## Connect from your host machine Inside Laradock, other containers reach the broker at `kafka:9092`. From your own machine, it's published on `localhost:9092`. Note `KAFKA_ADVERTISED_HOST_NAME`/`KAFKA_ADVERTISED_LISTENERS` are hardcoded to `127.0.0.1` in `compose.yml`, if you need clients on other machines on your network to connect, you'll need to edit those values directly. ## Start completely fresh (wipe all data) To throw away every topic and offset and start Kafka from a clean, empty state (⚠️ this **permanently deletes** all topics and their data, there is no built-in export/import for this, so only do it if you don't need the data): ```bash ./laradock stop kafka zookeeper ./laradock remove kafka zookeeper rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/kafka" "${DATA_PATH_HOST:-~/.laradock/data}/zookeeper" ./laradock start zookeeper kafka ``` ```bash docker compose stop kafka zookeeper docker compose rm -sf kafka zookeeper rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/kafka" "${DATA_PATH_HOST:-~/.laradock/data}/zookeeper" docker compose up -d zookeeper kafka ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default). Wipe both `kafka` and `zookeeper`'s folders together, a Kafka broker with no matching ZooKeeper state (or vice versa) won't come back up cleanly. ## Common issues - **Kafka won't start.** It depends on ZooKeeper being up first; always start both together with `./laradock start zookeeper kafka`. - **Client can't produce/consume even though the container is running.** Confirm your client is using `kafka:9092` from inside another container, or `localhost:9092` from your host, not a mix of the two. - **Message rejected as too large.** Check `KAFKA_MESSAGE_MAX_BYTES` (fixed at `2000000` in `compose.yml`); anything bigger needs the compose file edited directly since it's not exposed via `.env`. - **Nothing shows up in Kafka Manager.** Make sure `zookeeper` and `kafka` are both running before adding the cluster, and that you pointed the cluster form at `zookeeper:2181`, not `kafka:9092`. - **Topic commands hang or time out.** They talk to ZooKeeper directly (`--zookeeper zookeeper:2181`), confirm the `zookeeper` container is up with `./laradock logs zookeeper`. --- Need a web UI for the cluster? See **[Kafka Manager](https://laradock.io/docs/services/kafka-manager)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Laravel Echo Server Source: https://laradock.io/docs/services/laravel-echo-server ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Echo Server? [Laravel Echo Server](https://github.com/tlaverdure/laravel-echo-server) is a Node.js WebSocket server that implements the Pusher protocol for Laravel's broadcasting system, using Redis as its backing pub/sub layer. It's the older, community-maintained option that predates Laravel's first-party **[Reverb](https://laradock.io/docs/services/laravel-reverb)** and the Pusher-compatible **[Soketi](https://laradock.io/docs/services/soketi)**; both are generally preferred for new projects, but this remains available for existing apps already wired up to it. Laradock builds it from `node:alpine`. ## Start Laravel Echo Server ```bash ./laradock start laravel-echo-server ``` ```bash docker compose up -d laravel-echo-server ``` The container `links` to `redis` in `compose.yml` (it uses Redis as its pub/sub backend), so make sure Redis is running too. Start both together: ```bash ./laradock start redis laravel-echo-server ``` ```bash docker compose up -d redis laravel-echo-server ``` ## Stop Laravel Echo Server ```bash ./laradock stop laravel-echo-server ``` ```bash docker compose stop laravel-echo-server ``` To remove the container entirely (nothing persists on disk for this service, so there's no data to lose): ```bash ./laradock remove laravel-echo-server ``` ```bash docker compose rm -sf laravel-echo-server ``` ## Configuration `laravel-echo-server/defaults.env` holds the port, overridable by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `LARAVEL_ECHO_SERVER_PORT` | `6001` | Host-side port the WebSocket server is published on (`host:6001`). | Server behavior itself (auth endpoint, Redis connection, dev mode, and so on) is configured in `laravel-echo-server/laravel-echo-server.json`, mounted read-only into the container. Out of the box it points at Redis by container name (`host: "redis"`, `port: "6379"`), listens on port `6001`, and runs with `devMode: true`. ## Authenticating private and presence channels Laravel Echo Server needs to know how to validate a client before letting it join a private or presence channel. `laravel-echo-server.json` supports two approaches, and you can use either or both: - **`authHost` + `authEndpoint`** (the default): Echo Server forwards the auth check to your Laravel app, `authHost: "localhost"` and `authEndpoint: "/broadcasting/auth"` out of the box. Set `authHost` to wherever your app is actually reachable from the container if `localhost` doesn't resolve there. - **`clients`**: an array of `{ "appId": "...", "key": "..." }` pairs Echo Server can validate directly, without calling your app at all. Useful for server-to-server or API clients that already hold an app key. It's empty by default, add entries if you need it. ## Change the Laravel Echo Server version There's no version env var for this service, the npm package version is pinned in `laravel-echo-server/package.json`: ```json "dependencies": { "laravel-echo-server": "^1.5.0" } ``` Edit that version, then rebuild the image: ```bash ./laradock rebuild laravel-echo-server ``` ```bash docker compose build laravel-echo-server ``` ## Enable HTTPS/WSS By default the server speaks plain `http`/`ws` (`protocol: "http"` in `laravel-echo-server.json`). To serve over TLS instead, mount your certificate and key into the container, then point `sslCertPath` and `sslKeyPath` at them and set `protocol` to `"https"`: ```json "protocol": "https", "sslCertPath": "/path/inside/container/cert.pem", "sslKeyPath": "/path/inside/container/key.pem" ``` You'll need to add a volume mount for your certificate files in `laravel-echo-server/compose.yml` since only `laravel-echo-server.json` itself is mounted by default. ## Turn off dev mode for production `devMode: true` makes Echo Server log every connection, subscription, and disconnection, useful while wiring things up, noisy and unnecessary once broadcasting works. Set `devMode: false` in `laravel-echo-server.json` when you're done debugging. ## Connect from Laravel 1. In your Laravel `.env`, configure broadcasting for the Pusher driver (Echo Server speaks the Pusher protocol) and point Echo's frontend client at the container's published port, `localhost:6001` by default. 2. Set `REDIS_HOST=redis` so your app and Echo Server share the same Redis pub/sub backend, this is required, Echo Server only relays events published to Redis. 3. Start both containers: ```bash ./laradock start redis laravel-echo-server ``` ```bash docker compose up -d redis laravel-echo-server ``` ## Verify it's working With `devMode: true` (the default), Echo Server logs each client connection and channel subscription as it happens. Tail the logs while your frontend connects to confirm it's receiving traffic: ```bash ./laradock logs laravel-echo-server ``` ```bash docker compose logs --tail=100 laravel-echo-server ``` No logs when your app fires a broadcast event usually means the event never reached Redis, check `BROADCAST_CONNECTION` and `REDIS_HOST` in your Laravel `.env` first. ## Common issues - **No events arrive on the frontend.** Laravel publishes broadcast events to Redis; Echo Server only relays what it sees there. Confirm your app's `.env` uses `BROADCAST_CONNECTION=redis` (or your Pusher-compatible driver of choice) and the same `REDIS_HOST` as `laravel-echo-server.json`. - **Auth fails on private/presence channels.** `laravel-echo-server.json` sets `authEndpoint: "/broadcasting/auth"` and `authHost: "localhost"`; adjust `authHost` if your app isn't reachable at `localhost` from wherever Echo Server resolves it, or add a `clients` entry to bypass your app entirely. - **Port already in use on your host.** Another local WebSocket server (or another Laradock project) is already bound to `6001`. Change `LARAVEL_ECHO_SERVER_PORT` in `.env` and restart: `./laradock restart laravel-echo-server`. - **Config changes to `laravel-echo-server.json` don't take effect.** It's mounted read-only in `compose.yml`; a restart should pick up edits, but if not, rebuild: `./laradock rebuild laravel-echo-server`. --- Starting a new project? Prefer Laravel's own first-party server, **[Laravel Reverb](https://laradock.io/docs/services/laravel-reverb)**, or the Pusher-compatible **[Soketi](https://laradock.io/docs/services/soketi)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Laravel Horizon Source: https://laradock.io/docs/services/laravel-horizon ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Horizon? [Laravel Horizon](https://laravel.com/docs/horizon) is Laravel's official dashboard and configuration layer for Redis-backed queues, it doesn't replace the queue worker process, it supervises and reports on it. This container isn't a standalone daemon in the usual sense: it's a dedicated PHP/Alpine image (built via `supervisord`, extending Laradock's usual PHP extension-install pattern) whose job is to run `php artisan horizon` against your mounted Laravel application, under `depends_on: workspace`. ## First-run setup (required) The container ships with only an **example** supervisord program file, `laravel-horizon/supervisord.d/laravel-horizon.conf.example`. Supervisord only loads files matching `*.conf`, so on a fresh checkout it loads nothing and the container starts but never actually runs `php artisan horizon`. Copy the example once before your first start: ```bash cp laravel-horizon/supervisord.d/laravel-horizon.conf.example laravel-horizon/supervisord.d/laravel-horizon.conf ``` `*.conf` is gitignored on purpose (`laravel-horizon/supervisord.d/.gitignore`) so your local copy is never committed. Do this before [starting the container](#start-laravel-horizon), or [restart it](#supervise-queue-workers) afterward if you already started it without the file. ## Start Laravel Horizon Your app must already have Horizon installed (`composer require laravel/horizon`) and configured to use the `redis` queue connection. Then: ```bash ./laradock start laravel-horizon ``` ```bash docker compose up -d laravel-horizon ``` The container `depends_on` `workspace` in `compose.yml`, so Compose starts it first automatically. It also needs `redis` running and reachable, since that's what `php artisan horizon` actually connects to. ## Stop Laravel Horizon Stopping just pauses the container; horizon simply stops processing until you start it again: ```bash ./laradock stop laravel-horizon ``` ```bash docker compose stop laravel-horizon ``` This stops the container, which stops the supervised `horizon` process along with it. To remove the container: ```bash ./laradock remove laravel-horizon ``` ```bash docker compose rm -sf laravel-horizon ``` ## Configuration Laravel Horizon's own dashboard and queue settings live in your Laravel app (`config/horizon.php`), not in this container. What this container's `laravel-horizon/defaults.env` controls is which optional PHP extensions get compiled into its image at build time, all `false` by default: | Variable | Default | What it does | |---|---|---| | `LARAVEL_HORIZON_INSTALL_BZ2` | `false` | Install the `bz2` extension. | | `LARAVEL_HORIZON_INSTALL_GD` | `false` | Install the `gd` extension. | | `LARAVEL_HORIZON_INSTALL_GMP` | `false` | Install the `gmp` extension. | | `LARAVEL_HORIZON_INSTALL_GNUPG` | `false` | Install the `gnupg` extension. | | `LARAVEL_HORIZON_INSTALL_LDAP` | `false` | Install the `ldap` extension. | | `LARAVEL_HORIZON_INSTALL_IMAGEMAGICK` | `false` | Install `imagick`, version controlled by `LARAVEL_HORIZON_IMAGEMAGICK_VERSION`. | | `LARAVEL_HORIZON_INSTALL_INTL` | `false` | Install the `intl` extension. | | `LARAVEL_HORIZON_IMAGEMAGICK_VERSION` | `latest` | Git ref of the `imagick` PECL/source build, used only when ImageMagick is installed. | | `LARAVEL_HORIZON_INSTALL_SOCKETS` | `false` | Install the `sockets` extension. | | `LARAVEL_HORIZON_INSTALL_YAML` | `false` | Install the `yaml` extension. | | `LARAVEL_HORIZON_INSTALL_ZIP_ARCHIVE` | `false` | Install the `zip` extension. | | `LARAVEL_HORIZON_INSTALL_PHPREDIS` | `false` | Install the `redis` PECL extension (in addition to `predis`, if your app uses it). | | `LARAVEL_HORIZON_INSTALL_MONGO` | `false` | Install the `mongodb` extension. | | `LARAVEL_HORIZON_INSTALL_CASSANDRA` | `false` | Install the Cassandra PHP driver. | | `LARAVEL_HORIZON_INSTALL_FFMPEG` | `false` | Install the `ffmpeg` binary for jobs that process media. | | `LARAVEL_HORIZON_INSTALL_AUDIOWAVEFORM` | `false` | Install the BBC `audiowaveform` binary. | | `LARAVEL_HORIZON_INSTALL_POPPLER_UTILS` | `false` | Install `poppler-utils` and `antiword` for PDF/document jobs. | | `LARAVEL_HORIZON_PUID` | `1000` | UID for the container's `laradock` user. | | `LARAVEL_HORIZON_PGID` | `1000` | GID for the container's `laradock` user. | This container also inherits `PHP_FPM_INSTALL_PGSQL`, `PHP_FPM_INSTALL_BCMATH`, and `PHP_FPM_INSTALL_MEMCACHED` from the shared PHP-FPM build args, so those extensions follow whatever you've already set for `php-fpm`. ## Supervise queue workers The actual worker process(es) Horizon supervises are configured on the Laravel side, in `config/horizon.php` (queues, balance strategy, max processes, and so on), same as any Horizon setup. This container just needs Redis and your app code reachable to run `php artisan horizon`: ```bash ./laradock start redis workspace laravel-horizon ``` ```bash docker compose up -d redis workspace laravel-horizon ``` Supervisord config for the container itself lives in `laravel-horizon/supervisord.d` (see [First-run setup](#first-run-setup-required) if you haven't created `laravel-horizon.conf` yet), mounted straight into `/etc/supervisord.d`, edit it if you need to change how the `horizon` process is launched or restarted inside the container. It's a volume mount, not baked into the image, so a restart picks up your edit, no rebuild needed: ```bash ./laradock restart laravel-horizon ``` ```bash docker compose restart laravel-horizon ``` ## Manage Horizon from the CLI Open a terminal inside the container, the same way as any other Laradock service: ```bash ./laradock enter laravel-horizon ``` ```bash docker compose exec laravel-horizon bash ``` Then use Horizon's own Artisan commands, the same ones you'd use outside Docker: | Command | What it does | |---|---| | `php artisan horizon:status` | Print whether Horizon is currently running or paused. | | `php artisan horizon:pause` | Pause processing without stopping the container. | | `php artisan horizon:continue` | Resume after a pause. | | `php artisan horizon:terminate` | Gracefully stop after current jobs finish; supervisord (`autorestart=true`) restarts the process immediately, this is the standard way to pick up freshly deployed code without dropping in-flight jobs. | | `php artisan horizon:clear` | Remove all pending jobs from the queues Horizon is watching. | ## Common issues - **Horizon container is running but nothing shows in the dashboard.** You most likely skipped [First-run setup](#first-run-setup-required): without `laravel-horizon.conf`, supervisord has no program to run, so `php artisan horizon` never starts even though the container itself is healthy. - **Horizon container starts but no jobs process.** Confirm your Laravel app's `QUEUE_CONNECTION=redis` and that `redis` is running and reachable; Horizon only supervises Redis-backed queues. - **Missing PHP extension errors from your app's jobs.** The extension flags above are all `false` by default; if a job needs `gd`, `imagick`, `mongodb`, and so on, set the matching `LARAVEL_HORIZON_INSTALL_*` variable and rebuild: `./laradock rebuild laravel-horizon`. - **Extension build args changed but the container still lacks them.** These are Dockerfile build args, not runtime env vars; a plain restart won't apply them, rebuild the image after changing `.env`. - **Horizon dashboard (`/horizon`) shows no metrics.** That dashboard is served by your app itself (through `php-fpm`/`nginx`), not by this container; this container only needs to be running so the underlying queue actually gets worked. - **Edited `supervisord.d/laravel-horizon.conf` but nothing changed.** Supervisord only reads that file at process start; restart the container (`./laradock restart laravel-horizon`), don't just wait. --- Need the queue backend itself? See **[Redis](https://laradock.io/docs/services/redis)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Laravel Reverb Source: https://laradock.io/docs/services/laravel-reverb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Laravel Reverb? [Laravel Reverb](https://reverb.laravel.com) is Laravel's first-party WebSocket server, a modern, officially-maintained replacement for older options like `laravel-echo-server` or Soketi. This container runs `php artisan reverb:start` directly against your mounted application code rather than shipping a separate standalone server. ## Start Laravel Reverb 1. Install Reverb in your Laravel app (once): `php artisan install:broadcasting`, and set `BROADCAST_CONNECTION=reverb` in your app's `.env`. 2. Point Reverb at `0.0.0.0` in your app's `.env` so it's reachable from the host: `REVERB_HOST=0.0.0.0`, `REVERB_PORT=8080`. 3. Start the container: ```bash ./laradock start laravel-reverb ``` ```bash docker compose up -d laravel-reverb ``` The container `depends_on` `redis` in `compose.yml` (needed if you scale Reverb horizontally over Redis, see [Scale Reverb horizontally](#scale-reverb-horizontally) below), so Compose starts it automatically. ## Stop Laravel Reverb Stopping just pauses the container: ```bash ./laradock stop laravel-reverb ``` ```bash docker compose stop laravel-reverb ``` To remove the container entirely: ```bash ./laradock remove laravel-reverb ``` ```bash docker compose rm -sf laravel-reverb ``` Reverb keeps no data of its own on disk (it's not a stateful service), so there's nothing to back up here, removing the container is safe at any time. ## Configuration `laravel-reverb/defaults.env` holds the port, overridable by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `LARAVEL_REVERB_PORT` | `8080` | Host-side port the WebSocket server is published on (`host:8080`), and the port the container's `reverb:start` command binds to. | The image (`laravel-reverb/Dockerfile`) is built from `php:${PHP_VERSION}-cli-alpine` with `pcntl`, `posix`, `sockets`, and the `redis` PECL extension installed, everything Reverb needs for its event loop and Redis-backed horizontal scaling. Your application code is mounted in from `APP_CODE_PATH_HOST`, same as the other PHP containers. ## Change the PHP version The container's PHP version tracks your project-wide `PHP_VERSION` in `.env` (passed in as the `LARADOCK_PHP_VERSION` build arg). After changing it, rebuild the image: ```bash ./laradock rebuild laravel-reverb ``` ```bash docker compose build laravel-reverb ``` ## Connect from your app The WebSocket server is available on host port `8080` (or your custom `LARAVEL_REVERB_PORT`). Configure Laravel Echo on the frontend to connect there with `forceTLS: false` for local development. ## Scale Reverb horizontally Reverb `depends_on` `redis` so it can coordinate connection state across multiple Reverb instances instead of holding it in a single process's memory. To turn this on, set `REVERB_SCALING_ENABLED=true` in your Laravel app's `.env` alongside your existing `REDIS_HOST`/`REDIS_PORT` settings (pointed at Laradock's `redis` service). This is a Laravel-level setting, not a Laradock one, restart the container after changing it so the new config is picked up: ```bash ./laradock restart laravel-reverb ``` ```bash docker compose restart laravel-reverb ``` ## View logs Reverb logs every connection, disconnection, and broadcast event to stdout, useful when a client can't connect or a broadcast isn't arriving: ```bash ./laradock logs laravel-reverb ``` ```bash docker compose logs --tail=100 laravel-reverb ``` ## Common issues - **Reverb starts but the browser can't connect.** Make sure `REVERB_HOST=0.0.0.0` in your Laravel app's `.env`, if it's left at the default `localhost`, Reverb only binds inside the container and is unreachable from the host. - **Port already in use on your host.** Another local WebSocket server (or another Laradock project) is already bound to `8080`. Change `LARAVEL_REVERB_PORT` in `.env` and restart: `./laradock restart laravel-reverb`. - **Broadcasting still uses Pusher or another driver.** Confirm `BROADCAST_CONNECTION=reverb` is set in your Laravel app's `.env`, not just in the container config. - **App code changes don't show up.** The container runs `reverb:start` against your mounted `APP_CODE_PATH_HOST`; code changes apply on the next request as usual, but Reverb itself needs a restart to pick up config changes (`REVERB_*` env vars): `./laradock restart laravel-reverb`. - **Connections drop or state resets across multiple Reverb instances.** Check that `redis` is running (`./laradock logs redis`) and that `REVERB_SCALING_ENABLED=true` is actually set in your app's `.env`, not just assumed from `depends_on`. --- Need the older Node-based alternative? See **[Laravel Echo Server](https://laradock.io/docs/services/laravel-echo-server)**. Need a Pusher-protocol server instead? See **[Soketi](https://laradock.io/docs/services/soketi)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Memcached Source: https://laradock.io/docs/services/memcached ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Memcached? [Memcached](https://memcached.org) is a simple, high-performance in-memory key-value cache. Unlike Redis, it has no persistence and no built-in data structures (lists, sets, hashes), it's pure cache: store a value, get it back fast, let it expire. That simplicity makes it lighter and sometimes faster for pure caching workloads where you don't need Redis's extra features. ## Start Memcached ```bash ./laradock start memcached ``` ```bash docker compose up -d memcached ``` The container's `compose.yml` declares `depends_on: php-fpm`, so starting `memcached` also starts `php-fpm` if it isn't running yet. ## Stop Memcached Stopping just pauses the container; nothing to worry about since Memcached holds no data on disk anyway: ```bash ./laradock stop memcached ``` ```bash docker compose stop memcached ``` To delete the container entirely: ```bash ./laradock remove memcached ``` ```bash docker compose rm -sf memcached ``` ## Configuration All settings live in `memcached/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MEMCACHED_HOST_PORT` | `11211` | Host-side port Memcached is published on (`host:container`), Memcached's standard port. | ## Use Memcached from Laravel 1. In your Laravel `.env`, set `CACHE_DRIVER=memcached`. 2. In `config/cache.php`, point the `memcached` connection's host at the container name: ```php 'memcached' => [ 'servers' => [ [ 'host' => 'memcached', 'port' => 11211, 'weight' => 100, ], ], ], ``` 3. Laravel's Memcached driver requires the PHP `memcached` extension in `php-fpm`/`workspace`; make sure it's installed and enabled in those containers. ## Check memory usage and stats Memcached speaks a simple text protocol, so you can query live stats with `nc` (netcat) from your host machine, no client library needed: ```bash printf 'stats\r\n' | nc -w 1 localhost 11211 ``` This prints counters like `bytes` (current memory used), `limit_maxbytes` (memory cap), `curr_items` (keys currently cached), `get_hits`/`get_misses`, and `evictions` (items dropped because memory ran out, a sign you need a bigger memory limit). Swap `11211` for your custom `MEMCACHED_HOST_PORT` if you changed it. ## Flush all cached keys There's no per-key delete UI, but you can wipe the entire cache instantly: ```bash printf 'flush_all\r\n' | nc -w 1 localhost 11211 ``` A `OK` response confirms every key was invalidated immediately. Unlike Redis's `FLUSHALL`, this doesn't free memory back to the OS, Memcached just marks existing items expired, memory is reused as new keys come in. ## Increase the memory limit Memcached's default in-memory cache size is **64MB** (the `-m` flag, stock upstream default), which fills up fast under real traffic and starts evicting keys. Override the container's startup command in `memcached/compose.yml` to raise it: ```yaml services: memcached: command: memcached -m 256 ``` Then apply it: ```bash ./laradock start memcached ``` ```bash docker compose up -d memcached ``` Other useful flags you can add the same way: `-c` (max simultaneous connections, default `1024`) and `-I` (max size of a single cached item, default `1MB`). ## Connect from your host machine Inside Laradock, other containers reach it by container name: `memcached:11211`. From your own machine, connect to `localhost:11211` (or your custom `MEMCACHED_HOST_PORT`) with a Memcached client library, or use `nc`/`telnet` directly for the ad-hoc `stats`/`flush_all` commands shown above. ## Common issues - **App can't connect but the container is running.** Confirm the app's config uses `memcached` (the container name) as the host, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Cache writes silently fail.** The PHP `memcached` extension isn't installed/enabled in `php-fpm` or `workspace`. Without it, Laravel's Memcached driver can't connect and cache operations no-op or throw depending on your error handling. - **Port already in use on your host.** Another local Memcached (or another Laradock project) is already bound to `11211`. Change `MEMCACHED_HOST_PORT` in `.env` and restart: `./laradock restart memcached`. - **Cached data vanishes on restart.** This is expected: Memcached has no persistence by design. If you need cached values to survive a restart, use Redis, Valkey, or Dragonfly instead. - **No built-in authentication.** Stock Memcached (what this image runs) accepts any connection that can reach its port, there's no username/password. Keep `MEMCACHED_HOST_PORT` off the public internet; it's meant to be reached from other containers or your local machine only. - **Keys keep getting evicted under load.** Check `evictions` in `stats` (see [Check memory usage and stats](#check-memory-usage-and-stats) above); a rising count means the memory limit is too small for your working set, see [Increase the memory limit](#increase-the-memory-limit). --- Need persistence or richer data structures? See **[Redis](https://laradock.io/docs/services/redis)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Mercure Source: https://laradock.io/docs/services/mercure ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mercure? [Mercure](https://mercure.rocks) is an open protocol and hub for pushing real-time updates to web and mobile clients using Server-Sent Events. It's the default real-time solution for Symfony and API Platform, and works as a lightweight alternative to WebSocket servers when you only need server-to-client push. Laradock builds it from the official `dunglas/mercure` image. ## Start Mercure ```bash ./laradock start mercure ``` ```bash docker compose up -d mercure ``` The hub keeps no persistent data on disk, there's no volume in `mercure/compose.yml`. All subscriptions and in-flight updates live in the running container's memory only, so a restart clears them, there's nothing to back up. Name any other services alongside it to start them together, for example `./laradock start mercure workspace`. ## Stop Mercure Stopping just pauses the container: ```bash ./laradock stop mercure ``` ```bash docker compose stop mercure ``` To remove the container entirely: ```bash ./laradock remove mercure ``` ```bash docker compose rm -sf mercure ``` Since there's no data volume, stopping and removing are functionally the same in terms of what's lost: any currently-open subscriptions and undelivered updates. Starting again gives you a clean hub. ## Configuration All settings live in `mercure/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MERCURE_NODE_HOST_HTTP_PORT` | `1337` | Host-side port for HTTP (`host:80`). | | `MERCURE_NODE_HOST_HTTPS_PORT` | `1338` | Host-side port for HTTPS (`host:443`). | | `MERCURE_PUBLISHER_JWT_KEY` | `secret` | Signing key used to validate JWTs from publishers. Change this for anything beyond local development. | | `MERCURE_SUBSCRIBER_JWT_KEY` | `another_secret` | Signing key used to validate JWTs from subscribers. Change this for anything beyond local development. | | `MERCURE_DEBUG` | `debug` | Passed through as the container's `DEBUG` environment variable. | | `MERCURE_SERVER_NAME` | `:80` | Passed through as the Caddy `SERVER_NAME` the Mercure hub binds to. | `mercure/compose.yml` also sets `MERCURE_EXTRA_DIRECTIVES` to allow CORS from any origin and to allow publishing from `http://localhost:` and its HTTPS equivalent. Edit that block in `mercure/compose.yml` directly if you need different origins. ## Publish and subscribe Inside Laradock, other containers reach the hub by container name: `mercure:80`. From your host machine (or the browser), use `http://localhost:1337` (or your custom `MERCURE_NODE_HOST_HTTP_PORT`). Publishing requires a JWT signed with `MERCURE_PUBLISHER_JWT_KEY` containing the topics you're allowed to publish to; subscribing (from the browser via `EventSource`) requires a JWT signed with `MERCURE_SUBSCRIBER_JWT_KEY` for private topics, or no JWT at all for public ones. See the [Mercure documentation](https://mercure.rocks/docs/hub/config) for the JWT claim format. ## Test it from the command line Every Mercure hub exposes the protocol's fixed endpoint, `/.well-known/mercure`, for both publishing and subscribing, useful for a quick sanity check without wiring up your app first. Subscribe to a topic (this blocks and streams events as they arrive, `-N` disables curl's output buffering): ```bash curl -N "http://localhost:1337/.well-known/mercure?topic=https://example.com/my-topic" ``` In a second terminal, publish an update to that same topic (`data` is the payload your subscribers receive): ```bash curl -X POST "http://localhost:1337/.well-known/mercure" \ -H "Authorization: Bearer " \ -d "topic=https://example.com/my-topic" \ -d 'data={"hello":"world"}' ``` You should see the update appear on the first terminal's stream. The publisher JWT must be signed (HS256) with your `MERCURE_PUBLISHER_JWT_KEY` and carry a `mercure.publish` claim covering the topic (`["*"]` to allow all topics during local testing). If the topic you're subscribing to is private, the subscribe request also needs an `Authorization` header with a JWT signed by `MERCURE_SUBSCRIBER_JWT_KEY`. ## Debug mode `MERCURE_DEBUG` (default `debug`) is passed straight through as the container's `DEBUG` variable, turning on more verbose logging from the underlying Caddy server. Tail it while reproducing a failing publish or subscribe: ```bash ./laradock logs mercure ``` ```bash docker compose logs --tail=100 mercure ``` ## Talk to this hub from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this hub by container name (`mercure`) out of the box. The ports are already published to your host (`MERCURE_NODE_HOST_HTTP_PORT`/`MERCURE_NODE_HOST_HTTPS_PORT`), so point the other project at your **host machine's** address instead, for example `http://host.docker.internal:1337` (Docker Desktop) from inside another project's containers. Make sure the two projects use different `MERCURE_NODE_HOST_HTTP_PORT` values if they're both running at once. ## Common issues - **`401 Unauthorized` when publishing.** The JWT must be signed with `MERCURE_PUBLISHER_JWT_KEY` and include the `mercure.publish` claim for the topics you're targeting. - **Browser can't subscribe via CORS.** `MERCURE_EXTRA_DIRECTIVES` in `mercure/compose.yml` already allows all origins (`cors_allowed_origins *`) by default; if you've narrowed it, make sure your frontend's origin is included. - **Port already in use on your host.** Another local Mercure hub (or another Laradock project) is already bound to `1337` or `1338`. Change `MERCURE_NODE_HOST_HTTP_PORT` / `MERCURE_NODE_HOST_HTTPS_PORT` in `.env` and restart with `./laradock restart mercure`. - **Using the default JWT keys in anything beyond local dev.** `secret` and `another_secret` are placeholders; change `MERCURE_PUBLISHER_JWT_KEY` and `MERCURE_SUBSCRIBER_JWT_KEY` in `.env` before this leaves your machine. - **Updates aren't reaching subscribers after a restart.** Expected: Mercure keeps no persistent state, subscriptions and undelivered updates don't survive a restart. Your app needs to resubscribe. --- Need Pusher-protocol WebSockets for Laravel Echo instead? See **[Soketi](https://laradock.io/docs/services/soketi)** or **[Laravel Reverb](https://laradock.io/docs/services/laravel-reverb)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Mosquitto Source: https://laradock.io/docs/services/mosquitto ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mosquitto? [Eclipse Mosquitto](https://mosquitto.org) is a lightweight open-source message broker implementing the MQTT protocol, widely used for IoT and lightweight pub/sub messaging. Laradock runs it as its own container so you can develop against a real MQTT broker without installing one on your host. ## Start Mosquitto ```bash ./laradock start mosquitto ``` ```bash docker compose up -d mosquitto ``` Retained messages and subscriptions are persisted to disk under `DATA_PATH_HOST/mosquitto/data` and survive restarts. Name any other services alongside it to start them together, for example `./laradock start mosquitto workspace`. ## Stop Mosquitto Stopping just pauses the container; **your persisted data is safe**: ```bash ./laradock stop mosquitto ``` ```bash docker compose stop mosquitto ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove mosquitto ``` ```bash docker compose rm -sf mosquitto ``` ## Configuration `mosquitto/defaults.env` holds the port, overridable by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MOSQUITTO_PORT` | `9001` | Host-side port Mosquitto is published on (`host:9001`). | The broker's listener itself is configured in `mosquitto/mosquitto.conf`, which is baked into the image at build time. It binds the default listener to port `9001` using the `websockets` protocol, not raw MQTT/TCP on `1883`. `allow_anonymous` isn't set in that file, so it falls back to Mosquitto's own compiled-in default. ## Apply a config change `mosquitto.conf` is copied into the image by `mosquitto/Dockerfile` at build time, so editing it locally has no effect until you rebuild and recreate the container: ```bash ./laradock rebuild mosquitto ``` ```bash docker compose build mosquitto ``` Then recreate the container on the new image: ```bash ./laradock start mosquitto ``` ```bash docker compose up -d mosquitto ``` ## Publish and subscribe Use an MQTT client that supports MQTT-over-WebSockets, for example [MQTT.js](https://github.com/mqttjs/MQTT.js): ```bash mqtt sub -t 'test' -h localhost -p 9001 -C 'ws' -v mqtt pub -t 'test' -h localhost -p 9001 -C 'ws' -m 'Hello!' ``` The `-C ws` flag matters: since the container's default listener speaks `websockets`, a plain TCP MQTT client pointed at port `9001` won't connect. ## Check broker stats Mosquitto publishes live broker stats (connected clients, message counts, uptime) to the `$SYS` topic tree. Subscribe to it with any WebSocket-capable client: ```bash mqtt sub -t '$SYS/#' -h localhost -p 9001 -C 'ws' -v ``` ## Require authentication By default the broker accepts anonymous connections. To require a username/password: 1. Create the password file inside the running container with Mosquitto's own tool: ```bash ./laradock enter mosquitto ``` ```bash docker compose exec mosquitto sh ``` ```bash mosquitto_passwd -c /mosquitto/config/passwd your_username ``` 2. Copy the generated file out to the `mosquitto/` folder on your host so it survives future rebuilds, then commit it alongside `mosquitto.conf`: ```bash docker compose cp mosquitto:/mosquitto/config/passwd ./mosquitto/passwd ``` 3. Add a `COPY passwd /mosquitto/config/` line to `mosquitto/Dockerfile` (right after the existing `COPY mosquitto.conf` line), and add these two lines to `mosquitto/mosquitto.conf`: ```conf allow_anonymous false password_file /mosquitto/config/passwd ``` 4. [Apply the config change](#apply-a-config-change) to rebuild and recreate the container. Clients now need `-u your_username -P yourpassword` to connect. ## View broker logs Mosquitto's own log file (`log_dest file /mosquitto/log/mosquitto.log` in `mosquitto.conf`) isn't on a mounted volume, only `/mosquitto/data` is, so it's lost whenever the container is removed. To read it while the container is still running: ```bash ./laradock enter mosquitto ``` ```bash docker compose exec mosquitto sh ``` ```bash cat /mosquitto/log/mosquitto.log ``` ## Backup and restore The broker persists retained messages and subscriptions to a single database file (`mosquitto.db` by default) under `DATA_PATH_HOST/mosquitto/data`. Stop the broker first so the file isn't being written to mid-copy: ```bash ./laradock stop mosquitto ``` ```bash docker compose stop mosquitto ``` ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/mosquitto/data" ./mosquitto-backup ``` Restore by stopping the broker, replacing the data folder with your backup, then starting it again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mosquitto/data" cp -r ./mosquitto-backup "${DATA_PATH_HOST:-~/.laradock/data}/mosquitto/data" ``` ```bash ./laradock start mosquitto ``` ```bash docker compose up -d mosquitto ``` ## Start completely fresh (wipe all data) To throw away every retained message and subscription and start Mosquitto from a clean, empty state (⚠️ this **permanently deletes** the persisted database, back up first if you need anything): ```bash ./laradock stop mosquitto ./laradock remove mosquitto rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mosquitto" ./laradock start mosquitto ``` ```bash docker compose stop mosquitto docker compose rm -sf mosquitto rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mosquitto" docker compose up -d mosquitto ``` ## Talk to this broker from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Mosquitto by container name out of the box. Easiest fix: publish the port (already done, `MOSQUITTO_PORT`) and have the other project's client connect to your **host machine's** address instead of `mosquitto`, for example `host.docker.internal` (Docker Desktop) on this project's `MOSQUITTO_PORT`, still over WebSockets (`-C ws`). Make sure the two projects use different `MOSQUITTO_PORT` values if they're both running at once. ## Common issues - **Client can't connect on port `9001`.** Confirm your client is configured for MQTT over WebSockets, not raw MQTT/TCP; the container's listener protocol is `websockets`, per `mosquitto/mosquitto.conf`. - **Need raw MQTT/TCP (port `1883`) instead.** Add an extra `listener` block to `mosquitto/mosquitto.conf` and expose the matching port in `mosquitto/compose.yml`, then [apply the config change](#apply-a-config-change). - **Port already in use on your host.** Another local MQTT broker (or another Laradock project) is already bound to `9001`. Change `MOSQUITTO_PORT` in `.env` and restart: `./laradock restart mosquitto`. - **Config changes to `mosquitto.conf` don't take effect.** The file is copied into the image at build time, so a plain restart won't pick up edits, you need to [apply the config change](#apply-a-config-change) (rebuild, then recreate the container). - **Logs look empty from `./laradock logs mosquitto`.** Mosquitto writes its own log to a file inside the container, not to stdout, so container logs stay mostly quiet. See [View broker logs](#view-broker-logs) instead. --- Need a queue instead of pub/sub messaging? See **[Beanstalkd](https://laradock.io/docs/services/beanstalkd)** or **[RabbitMQ](https://laradock.io/docs/services/rabbitmq)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # NATS Source: https://laradock.io/docs/services/nats ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is NATS? [NATS](https://nats.io) is a lightweight, high-performance messaging system for cloud-native and microservice architectures, used for pub/sub, request/reply, and simple queueing. Laradock runs the official `nats` image with its own config file baked in. ## Start NATS ```bash ./laradock start nats ``` ```bash docker compose up -d nats ``` ## Stop NATS Stopping just pauses the container. NATS in this setup keeps no persistent data volume, so there's nothing to preserve or lose either way: ```bash ./laradock stop nats ``` ```bash docker compose stop nats ``` To delete the container entirely: ```bash ./laradock remove nats ``` ```bash docker compose rm -sf nats ``` ## Configuration All settings live in `nats/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `NATS_CLIENT_PORT` | `4222` | Host-side port for client connections. | | `NATS_MONITORING_PORT` | `6222` | Host-side port for the clustering route port (mapped from the container's `6222`). | | `NATS_ROUTE_PORT` | `8222` | Host-side port for the HTTP monitoring endpoint (mapped from the container's `8222`). | The container's own `nats-server.conf` (baked into the image via `nats/Dockerfile`) sets the client port to `4222`, the HTTP monitoring port to `8222`, and a `cluster` block on port `6222` for connecting multiple NATS servers together. Note the naming in `defaults.env` doesn't line up 1:1 with what each port actually does inside the container: `NATS_MONITORING_PORT` maps to the container's clustering port `6222`, and `NATS_ROUTE_PORT` maps to the container's HTTP monitoring port `8222`. Double-check `nats/compose.yml` if you rely on a specific one. ## Change the server config `nats/nats-server.conf` is copied into the image at build time (`COPY nats-server.conf /etc/nats/nats-server.conf` in `nats/Dockerfile`), so editing it needs a rebuild, a plain restart won't pick up the change. After editing the file: ```bash ./laradock rebuild nats ./laradock start nats ``` ```bash docker compose build nats docker compose up -d nats ``` ## Enable clustering `nats-server.conf` ships with an empty `routes = []` list, so clustering to other NATS servers is off by default. To connect this server to others, add their `nats-route://` addresses to `routes` in `nats/nats-server.conf` and rebuild (see above). The `cluster` block's built-in `authorization` credentials for route connections are `ruser` / `T0pS3cr3t`, change these in `nats-server.conf` before exposing the cluster port (`NATS_MONITORING_PORT`, container `6222`) beyond your own machine. Full options are in the [NATS clustering docs](https://docs.nats.io/running-a-nats-service/configuration/clustering). ## Connect from your app Inside Laradock, other containers reach NATS by container name and its internal client port: `nats:4222`. From your host machine, connect to `localhost:4222` (or your custom `NATS_CLIENT_PORT`) with any NATS client library. ## Check server health The HTTP monitoring endpoint (container port `8222`, published on `NATS_ROUTE_PORT` by default) serves NATS's built-in monitoring JSON: ```bash curl http://localhost:8222/varz ``` A few other endpoints on the same port are useful day-to-day: | Endpoint | Shows | |---|---| | `/varz` | General server stats: uptime, connections, memory, CPU. | | `/connz` | Currently connected clients. | | `/subsz` | Active subscriptions. | | `/routez` | Cluster route connections (relevant once [clustering](#enable-clustering) is set up). | ## View logs ```bash ./laradock logs nats ``` ```bash docker compose logs --tail=100 nats ``` ## Talk to this NATS server from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this NATS by container name out of the box. Since the client port is already published (`NATS_CLIENT_PORT`), the other project can connect to your **host machine's** address instead of `nats`, for example `host.docker.internal:4222` (Docker Desktop) using this project's `NATS_CLIENT_PORT`. Make sure the two projects use different `NATS_CLIENT_PORT` values if they're both running at once. ## Common issues - **Port already in use on your host.** Another local NATS instance (or another Laradock project) is already bound to one of the default ports. Change the relevant `NATS_*_PORT` variable in `.env` and restart: `./laradock restart nats`. - **Monitoring/route ports feel swapped.** As noted above, `NATS_MONITORING_PORT` and `NATS_ROUTE_PORT` don't map to the container ports their names imply; check `nats/compose.yml` and `nats/nats-server.conf` directly if a specific port matters to you. - **Clustering doesn't work out of the box.** `nats-server.conf` ships with an empty `routes = []` list; see [Enable clustering](#enable-clustering) above. - **Config changes don't take effect.** `nats-server.conf` is copied into the image at build time, so a plain restart won't pick up edits, see [Change the server config](#change-the-server-config) above. --- Need a message queue with a management UI instead? See **[RabbitMQ](https://laradock.io/docs/services/rabbitmq)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # RabbitMQ Source: https://laradock.io/docs/services/rabbitmq ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is RabbitMQ? [RabbitMQ](https://www.rabbitmq.com) is a mature, widely-used message broker implementing AMQP, commonly used as a Laravel queue backend or for service-to-service messaging. Laradock builds it with the management plugin enabled, so you get the web dashboard out of the box. ## Start RabbitMQ ```bash ./laradock start rabbitmq ``` ```bash docker compose up -d rabbitmq ``` The container `depends_on` `php-fpm` in `compose.yml`, so Compose starts `php-fpm` first automatically. Your data (queues, exchanges, users) is created on first start and kept between restarts. ## Stop RabbitMQ Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop rabbitmq ``` ```bash docker compose stop rabbitmq ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/rabbitmq`): ```bash ./laradock remove rabbitmq ``` ```bash docker compose rm -sf rabbitmq ``` ## Configuration All settings live in `rabbitmq/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `RABBITMQ_NODE_HOST_PORT` | `5672` | Host-side port for the AMQP protocol (`host:5672`). | | `RABBITMQ_MANAGEMENT_HTTP_HOST_PORT` | `15672` | Host-side port for the management web UI over HTTP. | | `RABBITMQ_MANAGEMENT_HTTPS_HOST_PORT` | `15671` | Host-side port for the management web UI over HTTPS. | | `RABBITMQ_WEB_STOMP_HOST_PORT` | `15674` | Host-side port for Web STOMP (STOMP-over-WebSockets). | Default login credentials are set in `rabbitmq/rabbitmq.conf`: `default_user = guest`, `default_pass = guest`. ## Open the management UI Once the container is running, open [http://localhost:15672](http://localhost:15672) (or your custom `RABBITMQ_MANAGEMENT_HTTP_HOST_PORT`) and log in with `guest` / `guest`. The `rabbitmq_management` plugin is enabled at build time in `rabbitmq/Dockerfile`, so the dashboard is available without any extra setup. ## Connect from Laravel Inside Laradock, other containers reach RabbitMQ by container name: use host `rabbitmq`, port `5672`, with the credentials from `rabbitmq.conf`. Install a client such as `vladimir-yuldashev/laravel-queue-rabbitmq` in your app to wire it up as a queue driver. ## Change the default credentials Edit `rabbitmq/rabbitmq.conf`: ```conf default_user = your_user default_pass = your_password ``` That file is bind-mounted into the container (not baked into the image), so a restart is enough, no rebuild needed: ```bash ./laradock restart rabbitmq ``` ```bash docker compose restart rabbitmq ``` This only changes the credentials used for **new** installs (an empty `DATA_PATH_HOST/rabbitmq`). If the broker already has users provisioned from a previous boot, manage them from the management UI instead (`Admin` tab), or with `rabbitmqctl add_user`/`rabbitmqctl delete_user` after `./laradock enter rabbitmq`. ## Inspect queues Open a terminal inside the container and use `rabbitmqctl`: ```bash ./laradock enter rabbitmq ``` ```bash docker compose exec rabbitmq bash ``` Then, inside the container: ```bash rabbitmqctl list_queues name messages consumers ``` This lists every queue with its current depth (messages waiting) and consumer count, useful for spotting a stuck or backed-up queue without opening the management UI. The same UI shows this under **Queues and Streams**. ## Backup and restore RabbitMQ's own backup mechanism exports **definitions** (queues, exchanges, bindings, users, vhosts, policies), not the messages currently sitting in queues, since queues are meant to drain, not archive: ```bash ./laradock exec -T rabbitmq rabbitmqctl export_definitions - > definitions.json ``` ```bash docker compose exec -T rabbitmq rabbitmqctl export_definitions - > definitions.json ``` The `-` path tells `rabbitmqctl` to write to stdout instead of a file inside the container; the `-T` disables the container's pseudo-terminal so the JSON isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) definitions** from that file: ```bash ./laradock exec -T rabbitmq rabbitmqctl import_definitions - < definitions.json ``` ```bash docker compose exec -T rabbitmq rabbitmqctl import_definitions - < definitions.json ``` If you need the in-flight messages themselves preserved (not just topology), stop the broker and copy the whole data folder instead, see [Start completely fresh](#start-completely-fresh-wipe-all-data) for where it lives. ## Start completely fresh (wipe all data) To throw away everything and start RabbitMQ from a clean, empty state (⚠️ this **permanently deletes** every queue, exchange, and user in this container, export your definitions first if you need them): ```bash ./laradock stop rabbitmq ./laradock remove rabbitmq rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/rabbitmq" ./laradock start rabbitmq ``` ```bash docker compose stop rabbitmq docker compose rm -sf rabbitmq rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/rabbitmq" docker compose up -d rabbitmq ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above (mounted to `/var/lib/rabbitmq` in the container) is where RabbitMQ's node data actually lives on your machine. Deleting it and starting again re-creates the default `guest`/`guest` user and an empty broker, exactly like a brand-new install. ## Talk to this broker from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this RabbitMQ by container name out of the box. Easiest fix: publish the port (already done, `RABBITMQ_NODE_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `rabbitmq`, for example `host.docker.internal` (Docker Desktop) on this project's `RABBITMQ_NODE_HOST_PORT`. Make sure the two projects use different `RABBITMQ_*_HOST_PORT` values if they're both running at once. ## Common issues - **Can't log in to the management UI.** Credentials come from `rabbitmq/rabbitmq.conf` (`guest`/`guest` by default), not from `.env`. If you changed that file, restart: `./laradock restart rabbitmq`. - **Port already in use on your host.** Another local RabbitMQ (or another Laradock project) is bound to one of the default ports. Change the relevant `RABBITMQ_*_HOST_PORT` variable in `.env` and restart. - **App can't connect but the container is running.** Confirm the app's config uses host `rabbitmq` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Queue keeps growing / nothing is consuming it.** Check `rabbitmqctl list_queues name messages consumers` (see [Inspect queues](#inspect-queues)) β€” a consumer count of `0` means no worker is listening on that queue. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same RabbitMQ data on disk. --- Need something lighter for pub/sub? See **[Mosquitto](https://laradock.io/docs/services/mosquitto)** or **[NATS](https://laradock.io/docs/services/nats)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Redis Cluster Source: https://laradock.io/docs/services/redis-cluster ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Redis Cluster? [Redis Cluster](https://redis.io/docs/management/scaling/) is Redis's built-in sharding and high-availability mode, spreading keys across multiple nodes instead of running a single instance. Laradock's `redis-cluster` service runs six cluster nodes (three masters, three replicas) inside a single container, for local development and testing against cluster-mode client code, not for production-grade multi-node redundancy. ## Start Redis Cluster ```bash ./laradock start redis-cluster ``` ```bash docker compose up -d redis-cluster ``` The container builds and bootstraps a fresh six-node cluster every time it starts (see [No persistent data](#no-persistent-data) below), so give it a few seconds after start before connecting. ## Stop Redis Cluster Stopping just pauses the container; the cluster's in-memory state is preserved as long as the container itself isn't removed: ```bash ./laradock stop redis-cluster ``` ```bash docker compose stop redis-cluster ``` To delete the container: ```bash ./laradock remove redis-cluster ``` ```bash docker compose rm -sf redis-cluster ``` Unlike most other stateful Laradock services, **this permanently deletes all cluster data**, see the next section. ## No persistent data `redis-cluster/compose.yml` mounts no volume for this service (unlike `redis`, which binds `DATA_PATH_HOST/redis`). Everything the cluster holds lives only in the container's own writable layer, so it survives a `stop`/`start` cycle but is gone for good after `remove`/`rm`. Treat this service as scratch space for exercising cluster-mode client code, not as a place to keep data you care about. ## Configuration All settings live in `redis-cluster/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `REDIS_CLUSTER_PORT_RANGE` | `7000-7005` | Host-side port range published for the six cluster nodes (`host:container`), matches Redis Cluster's default bus/client port range. | There's no `REDIS_CLUSTER_PASSWORD` variable: unlike the plain `redis` service, this container is started with no `--requirepass`, so it has no authentication by default. ## Connect with redis-cli Cluster mode needs the `-c` flag so the client follows `MOVED`/`ASK` redirects between nodes, plus a `-p` pointing at any one of the six node ports: ```bash ./laradock enter redis-cluster redis-cli -c -p 7000 ``` ```bash docker compose exec redis-cluster bash redis-cli -c -p 7000 ``` ## Check cluster health From inside the `redis-cli -c -p 7000` prompt above: ``` CLUSTER INFO CLUSTER NODES ``` `CLUSTER INFO` should report `cluster_state:ok` and `cluster_known_nodes:6` once the container has finished bootstrapping. `CLUSTER NODES` lists each node's ID, address, role (`master`/`slave`), and the hash slot range it owns. ## Flush all keys Cluster mode doesn't support a single `FLUSHALL` that reaches every node from one connection; run it against each master: ``` redis-cli -c -p 7000 flushall redis-cli -c -p 7001 flushall redis-cli -c -p 7002 flushall ``` Ports 7000-7002 are the three masters by default; check `CLUSTER NODES` if you need to confirm which ports currently hold that role on your machine. ## Use Redis Cluster from Laravel Configure the cluster in `config/database.php` (example uses phpredis, see the [Laravel Redis docs](https://laravel.com/docs/redis#configuration)): ```php 'redis' => [ 'client' => 'phpredis', 'options' => [ 'cluster' => 'redis', ], 'clusters' => [ 'default' => [ [ 'host' => 'redis-cluster', 'password' => null, 'port' => 7000, 'database' => 0, ], ], ], ], ``` ## Common issues - **Port conflicts with the plain `redis` service.** Both services default to Redis's standard ports; if you run both at once, make sure `REDIS_CLUSTER_PORT_RANGE` doesn't overlap with `REDIS_PORT`. - **`CLUSTER INFO` shows `cluster_state:fail` right after start.** The container needs a moment to assign hash slots across all six nodes on boot. Run `./laradock logs redis-cluster` and retry once it settles. - **App can't connect but the container is running.** Confirm your app's config uses `redis-cluster` (the container name) as the host, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Client library errors on cluster commands.** Not every Redis client supports cluster mode; phpredis (used above) and Predis (with cluster config) both do, but make sure you're not accidentally pointing a plain single-node client at it. - **Data vanished after restarting Laradock.** Expected, see [No persistent data](#no-persistent-data): this service has no data volume, so removing the container (`./laradock remove redis-cluster`, or any full `docker compose down`) wipes it. --- Just need a single Redis instance? See **[Redis](https://laradock.io/docs/services/redis)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Redis WebUI Source: https://laradock.io/docs/services/redis-webui ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Redis WebUI? Redis WebUI is a lightweight browser-based admin panel for Redis: browse keys, inspect values, and run basic operations without touching `redis-cli`. In Laradock it's pre-wired to connect to the `redis` service automatically. ## Start Redis WebUI ```bash ./laradock start redis-webui ``` ```bash docker compose up -d redis-webui ``` The container's `compose.yml` declares `depends_on: redis`, so starting `redis-webui` also starts `redis` if it isn't running yet. ## Stop Redis WebUI ```bash ./laradock stop redis-webui ``` ```bash docker compose stop redis-webui ``` Redis WebUI keeps no data of its own (it's just a UI on top of `redis`), so there's nothing to lose by stopping, removing, or rebuilding it. ## Configuration All settings live in `redis-webui/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `REDIS_WEBUI_USERNAME` | `laradock` | Login username for the web panel. | | `REDIS_WEBUI_PASSWORD` | `laradock` | Login password for the web panel. | | `REDIS_WEBUI_CONNECT_HOST` | `redis` | Host of the Redis instance the panel connects to (the `redis` container name). | | `REDIS_WEBUI_CONNECT_PORT` | `6379` | Port of that Redis instance (container-internal, not `REDIS_PORT`). | | `REDIS_WEBUI_PORT` | `9987` | Host-side port the web panel itself is published on. | The panel's Redis connection also picks up `REDIS_PASSWORD` (defined in the main `.env`, shared with the `redis` service, `secret_redis` by default) to authenticate. ## Log in Open [http://localhost:9987](http://localhost:9987) (or your custom `REDIS_WEBUI_PORT`) and sign in with `REDIS_WEBUI_USERNAME` / `REDIS_WEBUI_PASSWORD`. It should already be connected to the `redis` container, no extra connection setup needed for the default single-instance setup. ## Point it at a different Redis instance Set `REDIS_WEBUI_CONNECT_HOST` and `REDIS_WEBUI_CONNECT_PORT` in `.env` to another container's name and internal port (for example `valkey` and `6379`), then apply the change: ```bash ./laradock start redis-webui ``` ```bash docker compose up -d redis-webui ``` Environment variable changes only take effect on container recreation, a plain `restart` isn't enough here, re-run `start`/`up -d` as shown above. ## Connect to more than one Redis instance at once The underlying image ([phpRedisAdmin](https://github.com/ErikDubbelboer/phpRedisAdmin)) supports listing multiple servers in its sidebar, it just needs one numbered set of environment variables per instance (`REDIS_1_HOST`/`REDIS_1_PORT`/`REDIS_1_AUTH`, `REDIS_2_HOST`/`REDIS_2_PORT`/`REDIS_2_AUTH`, and so on). Laradock's `redis-webui/compose.yml` only wires up `REDIS_1_*` (mapped from `REDIS_WEBUI_CONNECT_HOST`/`REDIS_WEBUI_CONNECT_PORT`/`REDIS_PASSWORD`) for the default single-instance setup. To browse a second instance (say `valkey`) in the same panel, add a matching `REDIS_2_*` block to the `environment:` section of `redis-webui/compose.yml`, then rebuild: ```bash ./laradock rebuild redis-webui ``` ```bash docker compose build redis-webui ``` ## Common issues - **Blank data or "connection refused" in the panel.** The `redis` container isn't up yet or crashed. Check `./laradock logs redis` and confirm it's healthy before reloading the panel. - **Login fails with the default credentials.** Someone already changed `REDIS_WEBUI_USERNAME`/`REDIS_WEBUI_PASSWORD` in `.env`; check there before assuming a bug. - **Panel shows no keys even though your app is caching.** Double-check `REDIS_WEBUI_CONNECT_HOST`/`PORT` actually point at the Redis instance your app writes to; if you run multiple Redis-compatible services (Redis, Valkey, Dragonfly), it's easy to point the UI at the wrong one. - **Changed `.env` but the panel still connects to the old host/port.** Environment variable changes need the container recreated, not just restarted, run `./laradock start redis-webui` again (see [Point it at a different Redis instance](#point-it-at-a-different-redis-instance)). --- Prefer the command line? See **[Redis](https://laradock.io/docs/services/redis)** for `redis-cli` usage. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Redis Source: https://laradock.io/docs/services/redis ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Redis? [Redis](https://redis.io) is an in-memory data store used as a cache, session store, and queue backend. It's the most common performance upgrade for PHP apps once file-based caching or `array` sessions stop being enough, and Laravel supports it natively. ## Start Redis ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` ## Stop Redis Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop redis ``` ```bash docker compose stop redis ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove redis ``` ```bash docker compose rm -sf redis ``` ## Configuration `redis/defaults.env` holds the port, and the password lives in the main `.env` (uncomment/edit the line under the `### REDIS` section). Either can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `REDIS_PORT` | `6379` | Host-side port Redis is published on (`host:container`). | | `REDIS_PASSWORD` | `secret_redis` | Passed to the container as `--requirepass`; set it empty to disable auth. | ## Use Redis from Laravel 1. In your Laravel `.env`, set `REDIS_HOST=redis`. If that variable isn't there, edit `config/database.php` instead and replace the default `127.0.0.1` with `redis`: ```php 'redis' => [ 'cluster' => false, 'default' => [ 'host' => 'redis', 'port' => 6379, 'database' => 0, ], ], ``` 2. To use Redis for cache and sessions, set `CACHE_DRIVER=redis` and `SESSION_DRIVER=redis` in `.env`. 3. Install the client: ```bash composer require predis/predis:^1.0 ``` 4. Test it from Laravel: ```php \Cache::store('redis')->put('Laradock', 'Awesome', 10); ``` ## Use the redis-cli ```bash ./laradock enter redis ``` ```bash docker compose exec redis bash ``` Then start the client, authenticating if `REDIS_PASSWORD` is set: ```bash redis-cli -a secret_redis ``` ## Flush all keys (clear the cache) ⚠️ This **permanently deletes** every key in Redis, there's no undo. Useful when stale cached data is causing bugs and you just want a clean slate: ```bash ./laradock exec -T redis redis-cli -a secret_redis FLUSHALL ``` ```bash docker compose exec -T redis redis-cli -a secret_redis FLUSHALL ``` `FLUSHALL` clears every database inside Redis. To clear only the currently selected database (`database => 0` by default in Laravel's config above), use `FLUSHDB` instead. ## Check memory usage and stats ```bash ./laradock exec -T redis redis-cli -a secret_redis INFO memory ``` ```bash docker compose exec -T redis redis-cli -a secret_redis INFO memory ``` `INFO memory` reports `used_memory_human` (current usage) and `maxmemory_policy` (what Redis does when it hits a memory cap, if you've set one). Swap `memory` for `stats` (`INFO stats`) to see hit/miss counters, or run `DBSIZE` for a quick key count in the current database. ## Backup and restore Redis periodically snapshots its dataset to disk as `dump.rdb` under `/data` in the container, which maps to `DATA_PATH_HOST/redis/dump.rdb` on your host. To back up, force an immediate snapshot, then copy that file out: ```bash ./laradock exec -T redis redis-cli -a secret_redis SAVE ``` ```bash docker compose exec -T redis redis-cli -a secret_redis SAVE ``` ```bash cp "${DATA_PATH_HOST:-~/.laradock/data}/redis/dump.rdb" backup.rdb ``` **Restore** a snapshot by putting it back before Redis starts, since Redis only loads `dump.rdb` from disk on boot: ```bash ./laradock stop redis ``` ```bash docker compose stop redis ``` ```bash cp backup.rdb "${DATA_PATH_HOST:-~/.laradock/data}/redis/dump.rdb" ``` ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` ## Start completely fresh (wipe all data) To throw away everything (all keys, all snapshots) and start Redis from a clean, empty state (⚠️ this **permanently deletes** the data, back up first if you need anything): ```bash ./laradock stop redis ./laradock remove redis rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/redis" ./laradock start redis ``` ```bash docker compose stop redis docker compose rm -sf redis rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/redis" docker compose up -d redis ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Redis's `dump.rdb` actually lives on your machine. ## Talk to this Redis from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Redis by container name out of the box. Easiest fix: publish the port (already done, `REDIS_PORT`) and have the other project connect to your **host machine's** address instead of `redis`, for example `REDIS_HOST=host.docker.internal` (Docker Desktop) with `REDIS_PORT` and `REDIS_PASSWORD` matching this project's values. Make sure the two projects use different `REDIS_PORT` values if they're both running at once, and pick different `database =>` indexes (or a key prefix) if you don't want them to see each other's keys. ## Connect from your host machine Inside Laradock, other containers reach Redis by container name: `REDIS_HOST=redis`. From your own machine, connect to `localhost:6379` (or your custom `REDIS_PORT`) with a GUI like TablePlus or RedisInsight, using `REDIS_PASSWORD` if set. ## Common issues - **`NOAUTH Authentication required`.** `REDIS_PASSWORD` is set in `.env` but your client isn't sending it. Pass `-a ` to `redis-cli`, or set the password on your Laravel Redis connection config. - **App can't connect but the container is running.** Confirm the app's `.env` uses `REDIS_HOST=redis` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Port already in use on your host.** Another local Redis (or another Laradock project) is already bound to `6379`. Change `REDIS_PORT` in `.env` and restart: `./laradock restart redis`. - **Data disappears after `docker compose down -v`.** Redis data lives under `DATA_PATH_HOST/redis`; `-v` removes named volumes and, depending on your setup, can wipe it. Use `./laradock stop redis` if you just want to pause the container. - **Cached values from a previous session/database still show up.** You're probably sharing the same `database =>` index across two apps or two Laradock projects. See [Flush all keys](#flush-all-keys-clear-the-cache) above, or give each app its own database index. --- Need a GUI to browse keys? See **[Redis WebUI](https://laradock.io/docs/services/redis-webui)**. Need a Redis-compatible alternative? See **[Valkey](https://laradock.io/docs/services/valkey)** or **[Dragonfly](https://laradock.io/docs/services/dragonfly)**, or a multi-node setup, **[Redis Cluster](https://laradock.io/docs/services/redis-cluster)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Soketi Source: https://laradock.io/docs/services/soketi ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Soketi? [Soketi](https://soketi.app) is a fast, open-source WebSockets server that implements the Pusher protocol. It's a drop-in replacement for the hosted Pusher service, letting Laravel apps use `laravel-echo` and broadcasting locally without a Pusher account or internet access. Laradock builds it from the official `quay.io/soketi/soketi` image. ## Start Soketi ```bash ./laradock start soketi ``` ```bash docker compose up -d soketi ``` Soketi is stateless, there's no data volume to worry about, connections are simply dropped and re-established by clients on restart. ## Stop Soketi ```bash ./laradock stop soketi ``` ```bash docker compose stop soketi ``` To remove the container entirely: ```bash ./laradock remove soketi ``` ```bash docker compose rm -sf soketi ``` ## Configuration All settings live in `soketi/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SOKETI_NODE_VERSION` | `16-debian` | Node.js base image variant used when building. | | `SOKETI_BASE_IMAGE_TAG_PREFIX` | `latest` | Soketi image tag prefix, combined with `SOKETI_NODE_VERSION` to select the exact `quay.io/soketi/soketi` tag. | | `SOKETI_PORT` | `6001` | Host-side port the WebSockets server is published on (`host:6001`). | | `SOKETI_METRICS_SERVER_PORT` | `9601` | Host-side port for Soketi's Prometheus-compatible metrics endpoint. | Soketi's own app-level config comes from `soketi/config.json`, mounted read-only into the container at `/app/bin/config.json`. Out of the box it only sets `"debug": false`; edit that file to add app credentials, SSL, or other Soketi options (see the [Soketi config reference](https://docs.soketi.app/getting-started/installation/using-docker)). ## Change the Soketi version Set the version and/or image tag prefix in your `.env`: ```env SOKETI_NODE_VERSION=18-debian SOKETI_BASE_IMAGE_TAG_PREFIX=latest ``` Then rebuild: ```bash ./laradock rebuild soketi ``` ```bash docker compose build soketi ``` Restart the container afterward so it runs on the new image: ```bash ./laradock restart soketi ``` ```bash docker compose restart soketi ``` ## Connect from Laravel 1. Set your Laravel `.env` to broadcast over Pusher's protocol, pointed at Soketi instead of Pusher's servers: ```env BROADCAST_CONNECTION=pusher PUSHER_APP_ID=app-id PUSHER_APP_KEY=app-key PUSHER_APP_SECRET=app-secret PUSHER_HOST=soketi PUSHER_PORT=6001 PUSHER_SCHEME=http ``` 2. Configure `laravel-echo` on the frontend to point at the same host/port with `forceTLS: false`. 3. Start the container: ```bash ./laradock start soketi ``` ```bash docker compose up -d soketi ``` Since `config.json` doesn't define specific apps by default, Soketi runs in a mode that accepts any app ID/key/secret; see [Restrict to specific apps](#restrict-to-specific-apps-lock-down-credentials) below to lock it down. ## Restrict to specific apps (lock down credentials) The default `config.json` has no `appManager` block, so Soketi accepts **any** `PUSHER_APP_ID`/`PUSHER_APP_KEY`/`PUSHER_APP_SECRET` combination, fine for local development, not something you'd want on a shared or exposed environment. To restrict it to specific known apps, add an `appManager` block to `soketi/config.json`: ```json { "debug": false, "appManager": { "driver": "array", "array": { "apps": [ { "id": "app-id", "key": "app-key", "secret": "app-secret", "maxConnections": -1, "enableClientMessages": true, "enabled": true } ] } } } ``` Match `id`/`key`/`secret` to the `PUSHER_APP_ID`/`PUSHER_APP_KEY`/`PUSHER_APP_SECRET` your Laravel app already uses, then restart: ```bash ./laradock restart soketi ``` ```bash docker compose restart soketi ``` Only connections presenting one of the configured `id`/`key`/`secret` combinations are accepted once this block is present. ## Check the metrics endpoint Soketi exposes Prometheus-compatible metrics on `SOKETI_METRICS_SERVER_PORT` (`9601` by default), useful for confirming the server is actually receiving traffic without digging through logs: ```bash curl http://localhost:9601/metrics ``` This returns current connection counts, messages sent/received, and other counters in Prometheus text format, ready to scrape from Grafana/Prometheus if you're already running the [monitoring stack](https://laradock.io/docs/Intro#supported-services). ## Tail the logs Useful when a client reports it can't connect at all, or you want to confirm Soketi is receiving handshake attempts: ```bash ./laradock logs soketi ``` ```bash docker compose logs --tail=100 soketi ``` ## Common issues - **Frontend can't connect from the browser.** The browser connects to `localhost:6001` (or your custom `SOKETI_PORT`), not the container name `soketi`, that only resolves inside the Docker network. - **Port already in use on your host.** Another local WebSockets server (or another Laradock project) is already bound to `6001`. Change `SOKETI_PORT` in `.env` and restart with `./laradock restart soketi`. - **Config changes to `config.json` don't take effect.** It's mounted read-only via a bind mount in `soketi/compose.yml`, so edits should apply on `./laradock restart soketi`; if not, rebuild with `./laradock rebuild soketi`. - **Need metrics for monitoring.** See [Check the metrics endpoint](#check-the-metrics-endpoint) above. - **Anyone can connect with made-up credentials.** Expected by default, see [Restrict to specific apps](#restrict-to-specific-apps-lock-down-credentials) above to lock it down. --- Prefer Laravel's own first-party WebSocket server? See **[Laravel Reverb](https://laradock.io/docs/services/laravel-reverb)**. Using the older Node-based option? See **[Laravel Echo Server](https://laradock.io/docs/services/laravel-echo-server)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # SQS (local emulator) Source: https://laradock.io/docs/services/sqs ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is this SQS service? This container is **not** Amazon's real SQS, it's a local, API-compatible emulator so you can develop against SQS-shaped code without an AWS account or network access. Laradock builds it from [`roribio16/alpine-sqs`](https://github.com/roribio16/alpine-sqs), which bundles [ElasticMQ](https://github.com/softwaremill/elasticmq) (a Scala-based SQS-compatible server) with a small web management UI, run under `supervisord`. ## Start SQS ```bash ./laradock start sqs ``` ```bash docker compose up -d sqs ``` ## Stop SQS Stopping just pauses the container: ```bash ./laradock stop sqs ``` ```bash docker compose stop sqs ``` To remove the container (see [Queues and messages are not persisted](#queues-and-messages-are-not-persisted-by-default) below, restarting or removing the container already loses in-memory queue state either way): ```bash ./laradock remove sqs ``` ```bash docker compose rm -sf sqs ``` ## Configuration All settings live in `sqs/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SQS_NODE_HOST_PORT` | `9324` | Host-side port for the SQS-compatible API (`host:9324`). | | `SQS_MANAGEMENT_HTTP_HOST_PORT` | `9325` | Host-side port for the web management UI (`host:9325`). | `sqs/compose.yml` mounts `DATA_PATH_HOST/sqs` into the container at `/opt/custom`; that's where you can drop custom ElasticMQ config (queue definitions) if you need queues pre-created on boot. Check the [alpine-sqs README](https://github.com/roribio16/alpine-sqs) for the exact config format it expects there. ## Open the management UI ```bash ./laradock start sqs ``` ```bash docker compose up -d sqs ``` Open [http://localhost:9325](http://localhost:9325) (or your custom `SQS_MANAGEMENT_HTTP_HOST_PORT`) to browse queues and messages. ## Connect from Laravel Point Laravel's SQS queue driver at the container instead of AWS, using any placeholder key/secret (ElasticMQ doesn't validate them): ```env QUEUE_CONNECTION=sqs AWS_ACCESS_KEY_ID=local AWS_SECRET_ACCESS_KEY=local AWS_DEFAULT_REGION=elasticmq SQS_PREFIX=http://sqs:9324/queue SQS_QUEUE=default ``` Inside Laradock, other containers reach it by container name: `sqs:9324`. From your host machine, use `localhost:9324` (or your custom `SQS_NODE_HOST_PORT`). ## Create and inspect queues ElasticMQ speaks the real SQS API, so the standard AWS CLI works against it, you just point `--endpoint-url` at the container. From your host machine: ```bash aws --endpoint-url http://localhost:9324 sqs create-queue --queue-name default ``` ```bash aws --endpoint-url http://localhost:9324 sqs list-queues ``` ```bash aws --endpoint-url http://localhost:9324 sqs get-queue-attributes --queue-url http://localhost:9324/queue/default --attribute-names ApproximateNumberOfMessages ``` Any AWS access key/secret works (ElasticMQ doesn't validate credentials), but the CLI still requires them to be set, for example via `AWS_ACCESS_KEY_ID=local AWS_SECRET_ACCESS_KEY=local AWS_DEFAULT_REGION=elasticmq` in your shell. The same queue depth (`ApproximateNumberOfMessages`) and message contents are also visible in the [management UI](#open-the-management-ui), which is usually the faster way to check what's stuck in a queue while debugging. ## Queues and messages are not persisted by default ElasticMQ stores queues and messages **in memory**. Stopping, removing, or rebuilding the container throws away everything in every queue, there is no `DATA_PATH_HOST/sqs` message backup to restore from, that mount is only for a config file defining queues to auto-create on boot, not for the messages themselves. If your local workflow depends on queues existing every time you start the container, define them in a config file mounted at `/opt/custom` (see [Configuration](#configuration)) rather than relying on `create-queue` calls surviving a restart. ## Common issues - **Confusing this for real AWS SQS.** It's a local emulator (ElasticMQ under `alpine-sqs`); it has no relation to your actual AWS account, region, or billing, it's purely for local development. - **Queue not found.** ElasticMQ needs queues to exist before you can send to them; either [create the queue](#create-and-inspect-queues) first, or pre-define it in a config file mounted at `/opt/custom`. - **Messages or queues disappeared after a restart.** Expected, see [Queues and messages are not persisted](#queues-and-messages-are-not-persisted-by-default) above. - **Port already in use on your host.** Another local SQS emulator (or another Laradock project) is already bound to one of the default ports. Change `SQS_NODE_HOST_PORT` or `SQS_MANAGEMENT_HTTP_HOST_PORT` in `.env` and restart with `./laradock restart sqs`. - **App can't connect but the container is running.** Confirm your app's SQS endpoint/prefix uses host `sqs` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. --- Need a general-purpose queue instead? See **[RabbitMQ](https://laradock.io/docs/services/rabbitmq)** or **[Beanstalkd](https://laradock.io/docs/services/beanstalkd)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Tarantool Admin Source: https://laradock.io/docs/services/tarantool-admin ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Tarantool Admin? Tarantool Admin is a browser-based UI for inspecting and managing a Tarantool instance: browse spaces, run queries, and watch server state without dropping into the Lua console. ## Start Tarantool Admin ```bash ./laradock start tarantool tarantool-admin ``` ```bash docker compose up -d tarantool tarantool-admin ``` The admin panel only shows data once it's pointed at a running `tarantool` container, start both together. ## Stop Tarantool Admin ```bash ./laradock stop tarantool-admin ``` ```bash docker compose stop tarantool-admin ``` To delete the container entirely, this is safe any time since the panel holds no data of its own (all the data lives in the `tarantool` container, untouched): ```bash ./laradock remove tarantool-admin ``` ```bash docker compose rm -sf tarantool-admin ``` ## Configuration All settings live in `tarantool-admin/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `TARANTOOL_ADMIN_PORT` | `8002` | Host-side port the admin web UI is published on. | ## Open the admin panel 1. Open [http://localhost:8002](http://localhost:8002) (or your custom `TARANTOOL_ADMIN_PORT`). 2. Set **Hostname** to `tarantool`, the container name of the Tarantool service, your data then appears in the panel. ## Change the port Set `TARANTOOL_ADMIN_PORT` in your `.env`, then apply it: ```bash ./laradock restart tarantool-admin ``` ```bash docker compose restart tarantool-admin ``` `TARANTOOL_ADMIN_PORT` only changes the host-side port, the container itself always serves the UI on its internal port `80`, so no image rebuild is needed, a restart is enough. ## Common issues - **Blank panel / can't connect.** The `tarantool` container isn't running, or the Hostname field isn't set to `tarantool` (the container name). It won't resolve `localhost` since the UI runs inside its own container. - **Port already in use on your host.** Another local service (or another Laradock project) is already bound to `8002`. Change `TARANTOOL_ADMIN_PORT` in `.env` and restart: `./laradock restart tarantool-admin`. - **Changes made in the panel don't persist.** Data lives in the `tarantool` container's own storage, not in `tarantool-admin`; if you're losing data, check the Tarantool service and its `DATA_PATH_HOST/tarantool` volume, not this admin container. --- Need the Tarantool server itself? See **[Tarantool](https://laradock.io/docs/services/tarantool)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Tarantool Source: https://laradock.io/docs/services/tarantool ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Tarantool? [Tarantool](https://www.tarantool.io) is an in-memory computing platform that combines a database with an embedded Lua application server, used for fast key-value and relational-style workloads plus custom server-side logic written in Lua. ## Start Tarantool ```bash ./laradock start tarantool ``` ```bash docker compose up -d tarantool ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example to pair it with the admin web UI: `./laradock start tarantool tarantool-admin`. ## Stop Tarantool Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop tarantool ``` ```bash docker compose stop tarantool ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove tarantool ``` ```bash docker compose rm -sf tarantool ``` ## Configuration All settings live in `tarantool/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `TARANTOOL_PORT` | `3301` | Host-side port Tarantool is published on (`host:container`). | Lua scripts placed in `tarantool/lua` on your host are mounted into the container at `/opt/tarantool`. ## Use the interactive console ```bash ./laradock exec tarantool console ``` ```bash docker compose exec tarantool console ``` ## Use the admin web UI 1. Start the admin container too: `./laradock start tarantool tarantool-admin`. 2. Open [http://localhost:8002](http://localhost:8002) (or your custom `TARANTOOL_ADMIN_PORT`, see the **[Tarantool Admin](https://laradock.io/docs/services/tarantool-admin)** page). 3. Set **Hostname** to `tarantool`, your data then appears in the panel. See the [Tarantool documentation](https://www.tarantool.io/en/doc/latest/) for query and Lua scripting reference. ## Backup and restore Tarantool persists its in-memory data to disk as snapshot (`.snap`) and write-ahead-log (`.xlog`) files under `/var/lib/tarantool` in the container, mapped to `DATA_PATH_HOST/tarantool` on your host. Backing up is a matter of forcing a fresh snapshot, then copying that folder. **Force a snapshot** from the interactive console so the on-disk files reflect the current in-memory state: ```bash ./laradock exec tarantool console ``` ```bash docker compose exec tarantool console ``` Then, inside the console: ```lua box.snapshot() ``` **Copy the data directory** to back it up: ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/tarantool" ./tarantool-backup ``` **Restore** by stopping the container, replacing the data directory with your backup, then starting again: ```bash ./laradock stop tarantool ``` ```bash docker compose stop tarantool ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/tarantool" cp -r ./tarantool-backup "${DATA_PATH_HOST:-~/.laradock/data}/tarantool" ``` ```bash ./laradock start tarantool ``` ```bash docker compose up -d tarantool ``` ## Start completely fresh (wipe all data) To throw away everything and start Tarantool from a clean, empty state (⚠️ this **permanently deletes** all snapshots and logs in this container, back up first if you need anything): ```bash ./laradock stop tarantool ./laradock remove tarantool rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/tarantool" ./laradock start tarantool ``` ```bash docker compose stop tarantool docker compose rm -sf tarantool rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/tarantool" docker compose up -d tarantool ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Tarantool's data actually lives on your machine. ## Talk to this from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Tarantool by container name out of the box. Easiest fix: publish the port (already done, `TARANTOOL_PORT`) and have the other project connect to your **host machine's** address instead of `tarantool`, for example `host.docker.internal` (Docker Desktop) on this project's `TARANTOOL_PORT`. Make sure the two projects use different `TARANTOOL_PORT` values if they're both running at once. ## Common issues - **Admin UI shows no data.** It needs the hostname set explicitly to `tarantool` (the container name), not `localhost`, since it's connecting from inside another container. - **App can't connect but the container is running.** Confirm your client uses `tarantool` (the container name) as the host, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Port already in use on your host.** Another local Tarantool (or another Laradock project) is already bound to `3301`. Change `TARANTOOL_PORT` in `.env` and restart: `./laradock restart tarantool`. - **Lua scripts in `tarantool/lua` aren't picked up.** The folder is mounted at `/opt/tarantool` inside the container; confirm your init logic actually loads from that path. --- Need the admin panel? See **[Tarantool Admin](https://laradock.io/docs/services/tarantool-admin)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Valkey Source: https://laradock.io/docs/services/valkey ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Valkey? [Valkey](https://valkey.io) is the community-driven fork of Redis, created after Redis's 2024 license change moved it away from an open-source license. Valkey stays fully protocol-compatible with Redis, so any Redis client, including Laravel's, works against it unmodified. ## Start Valkey ```bash ./laradock start valkey ``` ```bash docker compose up -d valkey ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start valkey workspace`. ## Stop Valkey Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop valkey ``` ```bash docker compose stop valkey ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove valkey ``` ```bash docker compose rm -sf valkey ``` ## Configuration All settings live in `valkey/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `VALKEY_VERSION` | `8-alpine` | Image tag from [Valkey's Docker Hub](https://hub.docker.com/r/valkey/valkey). | | `VALKEY_PORT` | `6380` | Host-side port Valkey is published on (`host:container`). Deliberately not `6379`, so it can run alongside the `redis` service. | ## Change the Valkey version Set the version in your `.env`: ```env VALKEY_VERSION=8-alpine ``` Then apply the change: ```bash ./laradock rebuild valkey ``` ```bash docker compose build valkey ``` ## Use Valkey from Laravel Point any Redis client at it the same way you would Redis. In your Laravel `.env`: ```env REDIS_HOST=valkey REDIS_PORT=6379 ``` Note the app-side `REDIS_PORT` here is the container-internal port (`6379`), not `VALKEY_PORT`, containers talk to each other over the internal network, not the host-published port. ## Connect from your host machine Inside Laradock, other containers reach it by container name: `valkey:6379`. From your own machine, connect to `localhost:6380` (or your custom `VALKEY_PORT`) with any Redis-compatible GUI like TablePlus or RedisInsight. ## Connect with the native CLI Open a terminal inside the container and use `valkey-cli`, the Redis-protocol CLI client bundled with the image: ```bash ./laradock enter valkey valkey-cli ``` ```bash docker compose exec valkey bash valkey-cli ``` ``` 127.0.0.1:6379> PING PONG 127.0.0.1:6379> KEYS * ``` ## Check memory usage and stats Run a one-off `INFO` query without opening an interactive shell: ```bash ./laradock exec valkey valkey-cli INFO memory ``` ```bash docker compose exec valkey valkey-cli INFO memory ``` Swap `memory` for `stats` (hit/miss ratio, ops/sec, connections) or `keyspace` (key counts and expiry counts per logical database). Plain `INFO` with no section returns everything. ## Flush all keys ⚠️ This **permanently deletes** every key in every logical database on this instance, there's no undo: ```bash ./laradock exec valkey valkey-cli FLUSHALL ``` ```bash docker compose exec valkey valkey-cli FLUSHALL ``` To clear only the currently selected logical database instead of all of them, use `FLUSHDB` from inside `valkey-cli` after `SELECT `. ## Backup and restore Valkey persists to a single RDB snapshot file (`dump.rdb`) under its data volume. Trigger a synchronous save, then copy the file out while the container is still running: ```bash ./laradock exec valkey valkey-cli SAVE ``` ```bash docker compose exec valkey valkey-cli SAVE ``` ```bash cp "${DATA_PATH_HOST:-~/.laradock/data}/valkey/dump.rdb" ./valkey-backup.rdb ``` `SAVE` blocks the server until the snapshot finishes (fine for a small local cache; for a large dataset use `BGSAVE` instead and poll `INFO persistence` for `rdb_bgsave_in_progress:0` before copying). **Restore** a snapshot: stop the container, replace the data file, then start again so Valkey loads it on boot: ```bash ./laradock stop valkey ``` ```bash docker compose stop valkey ``` ```bash cp ./valkey-backup.rdb "${DATA_PATH_HOST:-~/.laradock/data}/valkey/dump.rdb" ``` ```bash ./laradock start valkey ``` ```bash docker compose up -d valkey ``` Since most Laradock apps only use Valkey as a cache/session/queue store rather than a source of truth, backups here are usually optional, take one before anything you can't easily regenerate (long-lived sessions, queued jobs not yet processed). ## Start completely fresh (wipe all data) To throw away every key and start Valkey from a clean, empty state (⚠️ this **permanently deletes** all data in this container, back up first if you need anything): ```bash ./laradock stop valkey ./laradock remove valkey rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/valkey" ./laradock start valkey ``` ```bash docker compose stop valkey docker compose rm -sf valkey rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/valkey" docker compose up -d valkey ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Valkey's RDB snapshot actually lives on your machine. ## Talk to this from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Valkey by container name out of the box. Easiest fix: the port is already published (`VALKEY_PORT`), have the other project connect to your **host machine's** address instead of `valkey`, for example `REDIS_HOST=host.docker.internal` (Docker Desktop) with `REDIS_PORT` set to this project's `VALKEY_PORT`. Make sure the two projects use different `VALKEY_PORT` values if they're both running at once. ## Common issues - **App can't connect but the container is running.** Confirm the app's config uses `valkey` (the container name) as the host, not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Confusing `VALKEY_PORT` with the internal port.** `VALKEY_PORT` (default `6380`) is only the host-side mapping. From inside another container, Valkey is always reachable on port `6379`. - **Port already in use on your host.** Another local Valkey/Redis (or another Laradock project) is already bound to `6380`. Change `VALKEY_PORT` in `.env` and restart: `./laradock restart valkey`. - **Running both `redis` and `valkey` together.** They're separate containers with separate data (`DATA_PATH_HOST/valkey` vs `DATA_PATH_HOST/redis`), decide which one your app actually points at before debugging "missing" cache data. - **Cached data survives a `FLUSHALL` you expected to clear everything.** Laravel's cache/session/queue connections can each target a different logical database (`0`-`15` by default); `FLUSHALL` clears all of them, `FLUSHDB` only the one currently selected. --- Prefer upstream Redis instead? See **[Redis](https://laradock.io/docs/services/redis)**. Want an even higher-throughput alternative? See **[Dragonfly](https://laradock.io/docs/services/dragonfly)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # ZooKeeper Source: https://laradock.io/docs/services/zookeeper ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is ZooKeeper? [Apache ZooKeeper](https://zookeeper.apache.org) is a centralized coordination service for distributed systems: configuration, naming, and synchronization. In Laradock it exists almost exclusively as a dependency for **[Kafka](https://laradock.io/docs/services/kafka)**, which uses it for broker coordination. You generally won't run ZooKeeper on its own. ## Start ZooKeeper ```bash ./laradock start zookeeper ``` ```bash docker compose up -d zookeeper ``` If you're using it for Kafka (the common case), start both together: ```bash ./laradock start zookeeper kafka ``` ```bash docker compose up -d zookeeper kafka ``` ## Stop ZooKeeper Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop zookeeper ``` ```bash docker compose stop zookeeper ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove zookeeper ``` ```bash docker compose rm -sf zookeeper ``` ## Configuration `zookeeper/defaults.env` holds the port, overridable by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `ZOOKEEPER_PORT` | `2181` | Host-side port ZooKeeper is published on (`host:2181`). | Data is persisted under `DATA_PATH_HOST/zookeeper/data` (snapshots) and `DATA_PATH_HOST/zookeeper/datalog` (transaction logs), mounted as volumes in `zookeeper/compose.yml`. ## Browse the data with the ZooKeeper CLI ZooKeeper's whole job is storing a tree of znodes, so day-to-day work usually means poking at that tree with `zkCli.sh`, bundled in the image and pre-connected to `localhost:2181`: ```bash ./laradock enter zookeeper ``` ```bash docker compose exec zookeeper bash ``` Then, inside the container: ```bash zkCli.sh ``` Once connected, list and inspect znodes (Kafka creates its own tree here once it's running): ``` ls / get /brokers/ids ``` ## Back up and restore data ZooKeeper's state is just the snapshot and transaction-log files under `DATA_PATH_HOST/zookeeper`, so backing it up is a plain file copy, no dump tool involved. Stop the container first so you don't copy files mid-write: ```bash ./laradock stop zookeeper ``` ```bash docker compose stop zookeeper ``` Then copy both data folders to a backup location: ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/zookeeper" ~/zookeeper-backup ``` Start it again when you're done: ```bash ./laradock start zookeeper ``` ```bash docker compose up -d zookeeper ``` To restore, stop ZooKeeper, replace `DATA_PATH_HOST/zookeeper` with your backed-up copy, then start it again the same way. ## Start completely fresh (wipe all data) To throw away ZooKeeper's entire tree and start from a clean, empty state (⚠️ this **permanently deletes** all znodes, including Kafka's broker/topic metadata if Kafka uses this instance, back up first if you need anything): ```bash ./laradock stop zookeeper ./laradock remove zookeeper rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/zookeeper" ./laradock start zookeeper ``` ```bash docker compose stop zookeeper docker compose rm -sf zookeeper rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/zookeeper" docker compose up -d zookeeper ``` If you also use Kafka against this ZooKeeper, wipe Kafka's data at the same time (see the [Common issues](#common-issues) note below on why leaving one stale breaks the other). ## Use it with Kafka Kafka's own `compose.yml` points at ZooKeeper by container name and internal port: `KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181`. As long as both containers are on the `backend` network (the default), no further wiring is needed, just start both as shown above. ## Common issues - **Kafka won't start / can't find its broker metadata.** Confirm `zookeeper` is actually running before or alongside `kafka`: `docker compose ps zookeeper`. - **Port already in use on your host.** Another local ZooKeeper (or another Laradock project) is already bound to `2181`. Change `ZOOKEEPER_PORT` in `.env` and restart: `./laradock restart zookeeper`. - **Stale cluster state after a Kafka rebuild.** ZooKeeper's data at `DATA_PATH_HOST/zookeeper` persists across restarts; if Kafka and ZooKeeper get out of sync (for example after wiping Kafka's data but not ZooKeeper's, or vice versa), clear both data directories and start fresh. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same ZooKeeper data on disk. --- Using this for event streaming? See **[Apache Kafka](https://laradock.io/docs/services/kafka)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Adminer Source: https://laradock.io/docs/services/adminer ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Adminer? [Adminer](https://www.adminer.org) is a single-file database admin GUI that supports MySQL, MariaDB, PostgreSQL, SQLite, and more from one login screen, a lighter alternative to running a dedicated GUI per database engine. There's nothing to "install", Laradock builds it as its own container and you just log in with credentials for whichever database you're already running. ## Start Adminer ```bash ./laradock start adminer ``` ```bash docker compose up -d adminer ``` Adminer itself holds no database data, it's just the GUI. Start whatever database it should connect to alongside it, for example `./laradock start adminer mysql`. ## Stop Adminer ```bash ./laradock stop adminer ``` ```bash docker compose stop adminer ``` To delete the container entirely (nothing important is lost, Adminer has no data of its own beyond the login session, see [Persist login sessions](#persist-login-sessions-across-restarts) below): ```bash ./laradock remove adminer ``` ```bash docker compose rm -sf adminer ``` ## Configuration All settings live in `adminer/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `ADM_PORT` | `8081` | Host-side port for the web UI (container port `8080`). | | `ADM_INSTALL_MSSQL` | `false` | Build flag, when `true`, installs `pdo_odbc`/`pdo_dblib` so Adminer can connect to SQL Server. | | `ADM_PLUGINS` | *(empty)* | Space-separated list of Adminer plugins to enable. | | `ADM_DESIGN` | `pepa-linha` | UI theme. | | `ADM_DEFAULT_SERVER` | `mysql` | Server pre-filled on the login screen, handy for an external server or a non-default container name. | ## Log in Open [http://localhost:8081](http://localhost:8081). Pick the system (MySQL, PostgreSQL, SQLite, ...), enter the server (container name, e.g. `mysql` or `postgres`), and the matching credentials. Adminer is attached to the same Docker network as every other Laradock service, so any running database container is reachable by its service name. ## Add SQL Server support 1. In `.env`, set `ADM_INSTALL_MSSQL=true`. 2. Rebuild: ```bash ./laradock rebuild adminer ``` ```bash docker compose build adminer ``` ## Load plugins 1. Set `ADM_PLUGINS` in `.env` to the plugin names you want, space-separated. 2. Some plugins need extra parameters and a custom file inside the container, see Adminer's [Loading plugins](https://hub.docker.com/_/adminer) instructions. 3. Recreate the container so the new environment value is picked up: ```bash ./laradock start adminer ``` ```bash docker compose up -d adminer ``` ## Pre-fill the login screen Typing the same server name on every login gets old fast. Set `ADM_DEFAULT_SERVER` in `.env` to the container name you connect to most (`mysql`, `postgres`, `mariadb`, ...), then recreate the container the same way as [Load plugins](#load-plugins) above. The login form's "Server" field now comes pre-filled, you still choose the system and enter credentials yourself. ## Persist login sessions across restarts Adminer's image declares `/sessions` as a volume for its "permanent login" feature, but Laradock doesn't mount it to your host by default, so any remembered session is lost when the container is removed or rebuilt. If you rely on staying logged in, add a bind mount to `adminer/compose.yml`: ```yaml services: adminer: volumes: - ${DATA_PATH_HOST}/adminer:/sessions ``` Then recreate the container: ```bash ./laradock start adminer ``` ```bash docker compose up -d adminer ``` ## Common issues - **SQL Server option missing.** `ADM_INSTALL_MSSQL` is a build-time flag, changing it requires a rebuild (`./laradock rebuild adminer`), not just a restart. - **Login rejected.** Adminer connects with whatever credentials you type in on the login form, it doesn't read `PMA_*`-style env vars for the target database. Use the same `MYSQL_USER`/`MYSQL_PASSWORD` (or the equivalent for your database) you'd use anywhere else. - **Can't reach a database by container name.** Use the Docker Compose service name (`mysql`, `postgres`, `mariadb`, ...) as the server, not `localhost`, that only works from your host machine. - **Stayed logged in, then suddenly logged out.** Login sessions live in the container's `/sessions` folder, which isn't persisted by default, see [Persist login sessions](#persist-login-sessions-across-restarts) above. Removing or rebuilding the container always logs you out unless you've mounted that folder. - **Port already in use on your host.** Change `ADM_PORT` in `.env` and restart with `./laradock restart adminer`. --- Prefer a MySQL-focused GUI instead? See **[phpMyAdmin](https://laradock.io/docs/services/phpmyadmin)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # ArangoDB Source: https://laradock.io/docs/services/arangodb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is ArangoDB? [ArangoDB](https://arangodb.com) is a multi-model database that combines document, graph, and key/value storage behind one query language, AQL. It's a graph-capable alternative to running Neo4j alongside a separate document store. Laradock runs it straight from the official `arangodb` image. ## Start ArangoDB ```bash ./laradock start arangodb ``` ```bash docker compose up -d arangodb ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start arangodb workspace`. ## Stop ArangoDB Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop arangodb ``` ```bash docker compose stop arangodb ``` Data is kept in the named `arangodb` Docker volume, not under `DATA_PATH_HOST`. To delete the container entirely (the volume, and everything in it, is still untouched): ```bash ./laradock remove arangodb ``` ```bash docker compose rm -sf arangodb ``` ## Configuration All settings live in `arangodb/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `ARANGODB_VERSION` | `3.12` | Image tag from the [official ArangoDB image](https://hub.docker.com/_/arangodb). | | `ARANGODB_PORT` | `8529` | Host-side port for the web UI and API (container port `8529`). | | `ARANGODB_ROOT_PASSWORD` | `secret` | Password for the `root` user. | ## Change the ArangoDB version Set the version in your `.env`: ```env ARANGODB_VERSION=3.11 ``` Then apply the change (ArangoDB is pulled by tag, not built locally, so starting it again is enough to pull the new tag): ```bash ./laradock start arangodb ``` ```bash docker compose up -d arangodb ``` Crossing a major version against existing data can require ArangoDB's own upgrade procedure, check [ArangoDB's upgrade docs](https://docs.arangodb.com) before jumping versions on a real dataset, or [back up first](#backup-and-restore). ## Open the web UI ``` http://localhost:8529 ``` Log in as `root` with `ARANGODB_ROOT_PASSWORD`. ## Check the API from the command line ```bash curl http://localhost:8529/_api/version ``` ## Use the arangosh shell Default root credentials are `root` / `secret` (`ARANGODB_ROOT_PASSWORD`). Open a terminal inside the ArangoDB container, then start the interactive shell: ```bash ./laradock enter arangodb arangosh --server.password secret ``` ```bash docker compose exec arangodb bash arangosh --server.password secret ``` ```js db._databases(); db._collections(); ``` ## Backup and restore **Export (back up) your data** to a folder inside the container, using ArangoDB's own `arangodump` tool: ```bash ./laradock exec arangodb arangodump --server.username root --server.password secret --output-directory /tmp/dump --overwrite true ``` ```bash docker compose exec arangodb arangodump --server.username root --server.password secret --output-directory /tmp/dump --overwrite true ``` Then copy the dump out to your host (no CLI shortcut for this one, it's a plain `docker compose cp`): ```bash docker compose cp arangodb:/tmp/dump ./arangodb-backup ``` **Restore (import) your data** from a dump folder: copy it into the container, then run `arangorestore`. ```bash docker compose cp ./arangodb-backup arangodb:/tmp/dump ``` ```bash ./laradock exec arangodb arangorestore --server.username root --server.password secret --input-directory /tmp/dump ``` ```bash docker compose exec arangodb arangorestore --server.username root --server.password secret --input-directory /tmp/dump ``` This dumps/restores the database `arangodump`/`arangorestore` default to (`_system`). Pass `--server.database ` to target a different one. ## Start completely fresh (wipe all data) To throw away everything and start ArangoDB from a clean, empty state (⚠️ this **permanently deletes** all databases, collections, and graphs, back up first if you need anything): ```bash ./laradock stop arangodb ./laradock remove arangodb ``` ```bash docker compose stop arangodb docker compose rm -sf arangodb ``` Unlike most Laradock database services, ArangoDB persists to a named Docker volume, not `DATA_PATH_HOST`, so removing the container alone doesn't wipe the data. Drop the volume too: ```bash docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_arangodb ``` Then start it again: ```bash ./laradock start arangodb ``` ```bash docker compose up -d arangodb ``` Not sure of the exact volume name on your machine? Run `docker volume ls | grep arangodb` to find it first. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this ArangoDB by container name out of the box. Easiest fix: publish the port (already done, `ARANGODB_PORT`) and have the other project connect to your **host machine's** address instead of `arangodb`, for example `host.docker.internal` (Docker Desktop) on this project's `ARANGODB_PORT`. Make sure the two projects use different `ARANGODB_PORT` values if they're both running at once. ## Common issues - **Changing `ARANGODB_VERSION` doesn't take effect.** ArangoDB is pulled by image tag, not built locally, restart after changing it: `./laradock start arangodb`. Crossing a major version against existing data can require ArangoDB's own upgrade procedure, check their docs before jumping versions on a real dataset. - **Data isn't where you expect.** Unlike most Laradock database services, ArangoDB persists to a named Docker volume (`arangodb`), not `DATA_PATH_HOST`. Use `docker volume inspect _arangodb` to find it on disk, or see [Start completely fresh](#start-completely-fresh-wipe-all-data) to wipe just that volume. - **Port already in use on your host.** Change `ARANGODB_PORT` in `.env` and restart: `./laradock restart arangodb`. - **Forgot the root password.** It's only applied on first boot into a fresh volume. If you changed `ARANGODB_ROOT_PASSWORD` after that, either reset it from inside `arangosh` or [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss). --- Need a different multi-model option? See **[SurrealDB](https://laradock.io/docs/services/surrealdb)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # Cassandra Source: https://laradock.io/docs/services/cassandra ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Cassandra? [Apache Cassandra](https://cassandra.apache.org) is a distributed, wide-column NoSQL database built for high availability and horizontal scale across many nodes with no single point of failure. Laradock runs it via the [Bitnami Cassandra image](https://hub.docker.com/r/bitnami/cassandra/) as a single-node instance for local development. ## Start Cassandra ```bash ./laradock start cassandra ``` ```bash docker compose up -d cassandra ``` `compose.yml` declares `depends_on: php-fpm`, so Docker Compose starts `php-fpm` automatically if it isn't already running. The container also runs `privileged: true`, which Cassandra's Bitnami image requires. Your data is created on first start and kept between restarts. ## Stop Cassandra Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop cassandra ``` ```bash docker compose stop cassandra ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/cassandra`): ```bash ./laradock remove cassandra ``` ```bash docker compose rm -sf cassandra ``` ## Configuration All settings live in `cassandra/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `CASSANDRA_VERSION` | `latest` | Image tag from [bitnami/cassandra on Docker Hub](https://hub.docker.com/r/bitnami/cassandra/). | | `CASSANDRA_TRANSPORT_PORT_NUMBER` | `7000` | Inter-node cluster communication port. | | `CASSANDRA_JMX_PORT_NUMBER` | `7199` | JMX connections port. | | `CASSANDRA_CQL_PORT_NUMBER` | `9042` | Client (CQL) port, what your app/driver connects to. | | `CASSANDRA_USER` | `cassandra` | Cassandra username. | | `CASSANDRA_PASSWORD_SEEDER` | `no` | Set `yes` on exactly one node in a cluster to have it change default credentials at initialization. | | `CASSANDRA_PASSWORD` | `cassandra` | Password for `CASSANDRA_USER`. | | `CASSANDRA_NUM_TOKENS` | `256` | Number of tokens for the node. | | `CASSANDRA_HOST` | *(empty)* | Hostname to configure Cassandra with; resolves to the machine IP if left empty. | | `CASSANDRA_CLUSTER_NAME` | `"My Cluster"` | Cluster name. | | `CASSANDRA_SEEDS` | *(empty)* | Hosts acting as Cassandra seeds for cluster discovery. | | `CASSANDRA_ENDPOINT_SNITCH` | `SimpleSnitch` | Snitch strategy, determines which data centers/racks nodes belong to. | | `CASSANDRA_ENABLE_RPC` | `true` | Enables the Thrift RPC endpoint. | | `CASSANDRA_DATACENTER` | `dc1` | Datacenter name (ignored under `SimpleSnitch`). | | `CASSANDRA_RACK` | `rack1` | Rack name (ignored under `SimpleSnitch`). | ## Connect with cqlsh Open a terminal inside the Cassandra container, then start `cqlsh`: ```bash ./laradock enter cassandra cqlsh -u cassandra -p cassandra ``` ```bash docker compose exec cassandra bash cqlsh -u cassandra -p cassandra ``` Use your own `CASSANDRA_USER`/`CASSANDRA_PASSWORD` if you changed them. From your host machine or another container, connect on `CASSANDRA_CQL_PORT_NUMBER` (`9042` by default) at `cassandra` (container name) or `localhost` (from the host). ## Check cluster status Cassandra can take a while to become ready on first boot, and a running container doesn't mean the node has finished starting. `nodetool status` is the standard way to check: ```bash ./laradock exec cassandra nodetool status ``` ```bash docker compose exec cassandra nodetool status ``` `UN` in the output means "Up, Normal", the node is fully joined and ready to serve queries. Anything else (`UJ` joining, `DN` down) means it's not ready yet. ## Backup and restore Cassandra stores everything under `/var/lib/cassandra` inside the container, which is bind-mounted straight from `DATA_PATH_HOST/cassandra` on your host. The simplest reliable backup is archiving that directory while the container is stopped: ```bash ./laradock stop cassandra tar -czf cassandra-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" . ./laradock start cassandra ``` ```bash docker compose stop cassandra tar -czf cassandra-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" . docker compose up -d cassandra ``` To restore, stop the container, replace the data folder with the backup, then start again: ```bash ./laradock stop cassandra rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" mkdir -p "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" tar -xzf cassandra-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" ./laradock start cassandra ``` ```bash docker compose stop cassandra rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" mkdir -p "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" tar -xzf cassandra-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" docker compose up -d cassandra ``` For a point-in-time backup **without** stopping the node, use Cassandra's own snapshot mechanism instead: ```bash ./laradock exec cassandra nodetool snapshot -t my_backup ``` ```bash docker compose exec cassandra nodetool snapshot -t my_backup ``` This hard-links the current on-disk SSTables into a `snapshots/my_backup` folder inside each table's data directory (still under `DATA_PATH_HOST/cassandra`), which you can then `tar` out while the node keeps running. Clear it afterward with `nodetool clearsnapshot -t my_backup` so it doesn't consume extra disk space forever. ## Start completely fresh (wipe all data) To throw away everything and start Cassandra from a clean, empty state (⚠️ this **permanently deletes** every keyspace in this container, back up first if you need anything): ```bash ./laradock stop cassandra ./laradock remove cassandra rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" ./laradock start cassandra ``` ```bash docker compose stop cassandra docker compose rm -sf cassandra rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/cassandra" docker compose up -d cassandra ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Cassandra's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization, so `CASSANDRA_USER`/`CASSANDRA_PASSWORD` and the rest of the config table apply fresh, exactly like a brand-new node. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Cassandra by container name out of the box. Easiest fix: the port is already published (`CASSANDRA_CQL_PORT_NUMBER`), so have the other project connect to your **host machine's** address instead of `cassandra`, for example `host.docker.internal` (Docker Desktop) with its CQL driver port set to this project's `CASSANDRA_CQL_PORT_NUMBER`. Make sure the two projects use different `CASSANDRA_CQL_PORT_NUMBER` (and `CASSANDRA_TRANSPORT_PORT_NUMBER`/`CASSANDRA_JMX_PORT_NUMBER`) values if they're both running at once. ## Common issues - **Container won't start / permission errors.** Cassandra's Bitnami image needs `privileged: true`, which `compose.yml` already sets; if your Docker setup restricts privileged containers (some CI runners, rootless Docker), it may fail to boot. - **Slow first boot.** Cassandra can take longer than other databases to become ready on first start. Check `./laradock logs cassandra` and confirm with `nodetool status` (see [Check cluster status](#check-cluster-status)) before connecting. - **Credential changes don't take effect.** Credentials are set at initialization; changing `CASSANDRA_USER`/`CASSANDRA_PASSWORD` afterward requires either a [fresh start](#start-completely-fresh-wipe-all-data) (data loss, back up first) or changing them through CQL directly. - **App can't connect but the container is running.** Confirm the app's driver config uses `cassandra` (the container name) as the host, not `localhost`, which only works from your host machine. - **Port already in use on your host.** Another service is bound to `7000`, `7199`, or `9042`. Change the relevant `CASSANDRA_*_PORT_NUMBER` in `.env` and restart with `./laradock restart cassandra`. --- Need a document database instead? See **[CouchDB](https://laradock.io/docs/services/couchdb)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # ClickHouse Source: https://laradock.io/docs/services/clickhouse ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is ClickHouse? [ClickHouse](https://clickhouse.com) is a column-oriented database built for fast analytical (OLAP) queries over very large datasets, the kind of workload row-oriented databases like MySQL or Postgres struggle with. Laradock builds it from the official ClickHouse Debian packages on top of Ubuntu, with an HTTP interface, a native TCP interface, and its own config and users files pre-wired. ## Start ClickHouse ```bash ./laradock start clickhouse ``` ```bash docker compose up -d clickhouse ``` The `clickhouse` service links to the `workspace` container, so it's reachable from there by container name once both are up. Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start clickhouse workspace`. ## Stop ClickHouse Stopping just pauses the container; **your data is safe**, it lives under `DATA_PATH_HOST/clickhouse`: ```bash ./laradock stop clickhouse ``` ```bash docker compose stop clickhouse ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove clickhouse ``` ```bash docker compose rm -sf clickhouse ``` ## Configuration All settings live in `clickhouse/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `CLICKHOUSE_VERSION` | `25.8.2.29` | Version of the `clickhouse-server`/`clickhouse-client` packages installed at build time. | | `CLICKHOUSE_GOSU_VERSION` | `1.17` | Version of [gosu](https://github.com/tianon/gosu) used by the entrypoint to drop root privileges. | | `CLICKHOUSE_USER` | `default` | Database user created on boot. | | `CLICKHOUSE_PASSWORD` | `HAHA` | Password for `CLICKHOUSE_USER`. Change this before using anything beyond local dev. | | `CLICKHOUSE_HTTP_PORT` | `8123` | Host-side port for the HTTP interface (container port `8123`). | | `CLICKHOUSE_CLIENT_PORT` | `9000` | Host-side port for the native TCP protocol used by `clickhouse-client` (container port `9000`). | | `CLICKHOUSE_NATIVE_PORT` | `9009` | Host-side port for the interserver replication port (container port `9009`). | | `CLICKHOUSE_CUSTOM_CONFIG` | `./clickhouse/config.xml` | Server config file mounted into the container. | | `CLICKHOUSE_USERS_CUSTOM_CONFIG` | `./clickhouse/users.xml` | Users/roles config file mounted into the container. | | `CLICKHOUSE_ENTRYPOINT_INITDB` | `./clickhouse/docker-entrypoint-initdb.d` | Folder of scripts auto-run on container start. | | `CLICKHOUSE_HOST_LOG_PATH` | `./logs/clickhouse` | Host folder ClickHouse writes its logs to. | ## Connect with clickhouse-client ```bash ./laradock enter clickhouse clickhouse-client --user default --password HAHA ``` ```bash docker compose exec clickhouse clickhouse-client --user default --password HAHA ``` Or from the `workspace` container, reach it by service name: `clickhouse-client --host clickhouse --user default --password HAHA`. ## Connect over HTTP ```bash curl "http://localhost:8123/?user=default&password=HAHA" -d "SELECT 1" ``` The HTTP interface also exposes a lightweight health check at `/ping`. ## Change the ClickHouse version Set the version in your `.env`: ```env CLICKHOUSE_VERSION=24.8.4.13 ``` Then apply the change: ```bash ./laradock rebuild clickhouse ``` ```bash docker compose build clickhouse ``` Because `CLICKHOUSE_VERSION` is a build argument (baked into the image at build time, not read at container start), a version change always needs a rebuild, not just a restart. ## Run scripts on container start Anything placed in `clickhouse/docker-entrypoint-initdb.d/` (`CLICKHOUSE_ENTRYPOINT_INITDB`) runs automatically: `.sh` files are executed (or sourced), `.sql` and `.sql.gz` files are piped into `clickhouse-client`. Unlike MySQL's init folder, ClickHouse's entrypoint re-runs everything in this folder **on every container start**, not just the first one, so keep the SQL in there idempotent (`CREATE TABLE IF NOT EXISTS`, `CREATE DATABASE IF NOT EXISTS`) or you'll get errors on the second boot. ## Backup and restore ClickHouse ships without a database-wide dump tool like `mysqldump`, so back up per table using the native format, which round-trips cleanly through `clickhouse-client`. **Export (back up) a table** to a file on your host: ```bash ./laradock exec -T clickhouse clickhouse-client --user default --password HAHA --query "SELECT * FROM default.your_table FORMAT Native" > your_table.native ``` ```bash docker compose exec -T clickhouse clickhouse-client --user default --password HAHA --query "SELECT * FROM default.your_table FORMAT Native" > your_table.native ``` Replace `default.your_table` with your database and table name. The `-T` disables the container's pseudo-terminal so the binary dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a table** from a `.native` file (the target table must already exist with a matching schema): ```bash ./laradock exec -T clickhouse clickhouse-client --user default --password HAHA --query "INSERT INTO default.your_table FORMAT Native" < your_table.native ``` ```bash docker compose exec -T clickhouse clickhouse-client --user default --password HAHA --query "INSERT INTO default.your_table FORMAT Native" < your_table.native ``` For a whole database, repeat the export/import per table (`SHOW TABLES FROM default` lists what to loop over), or query with `--query "SELECT * FROM default.your_table" --format Native` piped through a small shell loop. ## Start completely fresh (wipe all data) To throw away everything and start ClickHouse from a clean, empty state (⚠️ this **permanently deletes** every database and table in this container, back up first if you need anything): ```bash ./laradock stop clickhouse ./laradock remove clickhouse rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/clickhouse" ./laradock start clickhouse ``` ```bash docker compose stop clickhouse docker compose rm -sf clickhouse rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/clickhouse" docker compose up -d clickhouse ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where ClickHouse's data actually lives on your machine. Deleting it and starting again re-runs everything in `docker-entrypoint-initdb.d/`, exactly like a brand-new install. ## Change resource limits The container requests high `ulimits` (`nproc: 65535`, `nofile: 262144`), ClickHouse itself recommends this for production-grade workloads. If Docker on your host caps these lower, you'll see startup warnings in `./laradock logs clickhouse`; raise the limits in Docker Desktop's resource settings or your Docker daemon config. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this ClickHouse by container name out of the box. Easiest fix: the ports are already published (`CLICKHOUSE_HTTP_PORT`, `CLICKHOUSE_CLIENT_PORT`), so have the other project connect to your **host machine's** address instead of `clickhouse`, for example `--host host.docker.internal` (Docker Desktop) with the port set to this project's `CLICKHOUSE_CLIENT_PORT` or `CLICKHOUSE_HTTP_PORT`. Make sure the two projects use different port values if they're both running at once. ## Common issues - **Default password is `HAHA`.** It's genuinely the shipped default in `clickhouse/defaults.env`, set your own `CLICKHOUSE_PASSWORD` in `.env` before using this for anything beyond local dev. - **Config changes don't take effect.** `clickhouse/config.xml` and `clickhouse/users.xml` are bind-mounted, edits apply on container restart (`./laradock restart clickhouse`); no rebuild needed. Changing `CLICKHOUSE_VERSION` does require a rebuild: `./laradock rebuild clickhouse`. - **Client can't connect from another container.** Use the service name `clickhouse` as the host, not `localhost`, and the container-internal ports (`9000` native, `8123` HTTP), not the host-mapped ones. - **Logs directory missing on host.** `CLICKHOUSE_HOST_LOG_PATH` (`./logs/clickhouse` by default) needs to exist for the bind mount to work; create it if Docker complains on startup. - **Init script fails on the second boot.** Scripts in `docker-entrypoint-initdb.d/` run on every container start, not just the first, so non-idempotent SQL (a plain `CREATE TABLE` without `IF NOT EXISTS`) errors out after the first successful run. --- Need a search engine instead? See **[Manticore](https://laradock.io/docs/services/manticore)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # CouchDB Source: https://laradock.io/docs/services/couchdb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is CouchDB? [Apache CouchDB](https://couchdb.apache.org) is a document-oriented NoSQL database that stores JSON documents and exposes its entire API over plain HTTP, including a built-in web admin UI (Fauxton). It's built around multi-master replication, making it a common choice for offline-first and sync-heavy apps. Laradock runs it via the [official CouchDB image](https://hub.docker.com/_/couchdb). ## Start CouchDB ```bash ./laradock start couchdb ``` ```bash docker compose up -d couchdb ``` It runs as its own container with no `depends_on` in `compose.yml`. Name any other services alongside it to start them together, for example `./laradock start couchdb workspace`. ## Stop CouchDB Stopping just pauses the container; **your data is safe**, it persists under `DATA_PATH_HOST/couchdb/data`: ```bash ./laradock stop couchdb ``` ```bash docker compose stop couchdb ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove couchdb ``` ```bash docker compose rm -sf couchdb ``` ## Configuration `couchdb/defaults.env` only exposes one setting: | Variable | Default | What it does | |---|---|---| | `COUCHDB_PORT` | `5984` | Host-side port CouchDB's HTTP API and Fauxton UI are published on (`host:container`). | The Dockerfile doesn't set any admin username/password, so CouchDB starts in its default "admin party" mode with no authentication configured. Set that up yourself before exposing it beyond local development, see the [CouchDB Docker Hub page](https://hub.docker.com/_/couchdb) for the `COUCHDB_USER`/`COUCHDB_PASSWORD` environment variables supported by the base image if you need to add them (you'll need to add an `environment:` block for them in `couchdb/compose.yml`, since only `COUCHDB_PORT` is currently wired through). ## Access Fauxton and the HTTP API With the container running, open [http://localhost:5984/_utils](http://localhost:5984/_utils) (or your `COUCHDB_PORT`) for the Fauxton admin UI. The raw HTTP API is available at the same host/port, for example: ```bash curl http://localhost:5984/ ``` ## Backup and restore CouchDB has no separate dump tool bundled in this image, so the reliable way to back up is a filesystem copy of its data folder while the container is stopped (CouchDB's `.couch` files aren't safe to copy while it's writing to them). **Back up:** ```bash ./laradock stop couchdb ``` ```bash docker compose stop couchdb ``` ```bash tar -czf couchdb-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/couchdb" data ``` Then start it again with `./laradock start couchdb`. **Restore** into a fresh instance (see [Start completely fresh](#start-completely-fresh-wipe-all-data) below to clear out any existing data first): ```bash tar -xzf couchdb-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/couchdb" ``` Then `./laradock start couchdb`. For selective, per-document backups instead of the whole instance, CouchDB's own replication protocol can also push a database to a file or another CouchDB instance, see the [CouchDB replication docs](https://docs.couchdb.org/en/stable/replication/index.html). ## Compact a database CouchDB never overwrites data in place, every update appends to the file on disk, so long-lived databases grow larger than the data they actually hold. Reclaim that space with the compaction endpoint: ```bash curl -X POST -H "Content-Type: application/json" http://localhost:5984//_compact ``` Compaction runs in the background and is safe to run on a live database. There's no fixed schedule, run it whenever a database's file size looks out of proportion to its actual document count. ## Start completely fresh (wipe all data) To throw away everything and start CouchDB from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop couchdb ./laradock remove couchdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/couchdb" ./laradock start couchdb ``` ```bash docker compose stop couchdb docker compose rm -sf couchdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/couchdb" docker compose up -d couchdb ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where CouchDB's data actually lives on your machine. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this CouchDB by container name out of the box. Easiest fix: publish the port (already done, `COUCHDB_PORT`) and have the other project connect to your **host machine's** address instead of `couchdb`, for example `host.docker.internal` (Docker Desktop) on this project's `COUCHDB_PORT`. Make sure the two projects use different `COUCHDB_PORT` values if they're both running at once. ## Common issues - **No authentication by default.** Nothing in `couchdb/defaults.env` or the Dockerfile sets admin credentials, so the instance runs open. Fine for local dev; add `COUCHDB_USER`/`COUCHDB_PASSWORD` yourself if you need to lock it down (see [Configuration](#configuration) above). - **App can't connect but the container is running.** Confirm the app's config uses `couchdb` (the container name) as the host from inside other Laradock containers, not `localhost`, which only works from your host machine. - **Port already in use on your host.** Another local CouchDB (or another Laradock project) is already bound to `5984`. Change `COUCHDB_PORT` in `.env` and restart with `./laradock restart couchdb`. - **Data not persisting across rebuilds.** Confirm `DATA_PATH_HOST` in your root `.env` points somewhere stable; CouchDB's data lives under `DATA_PATH_HOST/couchdb/data`. - **Database file size keeps growing.** CouchDB's append-only storage model means deletes and updates don't shrink files automatically, run a [compaction](#compact-a-database) to reclaim space. --- Need a document database with stronger schema tooling? See **[MongoDB](https://laradock.io/docs/services/mongo)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Manticore Search Source: https://laradock.io/docs/services/manticore ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Manticore Search? [Manticore Search](https://manticoresearch.com) is an open-source search engine forked from Sphinx, built for fast full-text and vector search. It's a lighter-weight alternative to Elasticsearch or Solr, speaking its own SphinxQL dialect (MySQL wire protocol) as well as a JSON/HTTP API. Laradock runs it as its own container, built straight from the official `manticoresearch/manticore` image. ## Start Manticore ```bash ./laradock start manticore ``` ```bash docker compose up -d manticore ``` Name any other services alongside it to start them together, for example `./laradock start manticore workspace`. ## Stop Manticore Stopping just pauses the container; **your data is safe** (it lives under `DATA_PATH_HOST/manticore/data`): ```bash ./laradock stop manticore ``` ```bash docker compose stop manticore ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove manticore ``` ```bash docker compose rm -sf manticore ``` ## Configuration All settings live in `manticore/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MANTICORE_CONFIG_PATH` | `./manticore/config` | Folder mounted to `/etc/sphinxsearch`, holds `sphinx.conf`. | | `MANTICORE_API_PORT` | `9312` | Host-side port for the legacy Sphinx binary API (container port `9312`). | | `MANTICORE_SPHINXQL_PORT` | `9306` | Host-side port for SphinxQL, the MySQL-protocol query interface (container port `9306`). | | `MANTICORE_HTTP_PORT` | `9308` | Host-side port for the HTTP/JSON API (container port `9308`). | There's no `MANTICORE_VERSION` variable, the `manticore/Dockerfile` builds from `manticoresearch/manticore` unpinned, so it always pulls whatever tag is latest at build time. ## Query over SphinxQL SphinxQL speaks the MySQL protocol, so any MySQL client works: ```bash mysql -h127.0.0.1 -P9306 ``` No username or password is required by default. ## Query over HTTP ```bash curl -s http://localhost:9308/sql -d "query=show tables" ``` ## Create an index The bundled `manticore/config/sphinx.conf` defines one sample real-time index, `testrt`. You don't have to edit that file to add more, Manticore supports creating real-time tables straight from SphinxQL (no restart needed, and they persist across restarts): ```bash mysql -h127.0.0.1 -P9306 -e "CREATE TABLE products(title text, content text, gid int) rt_mem_limit='128M';" ``` Insert and query it the same way: ```bash mysql -h127.0.0.1 -P9306 -e "INSERT INTO products(id, title, content, gid) VALUES (1, 'first post', 'hello world', 10);" mysql -h127.0.0.1 -P9306 -e "SELECT * FROM products WHERE MATCH('hello');" ``` Indexes defined in `sphinx.conf` (like `testrt`) instead require a config edit and a restart, see [Common issues](#common-issues). ## Check index and server health ```bash mysql -h127.0.0.1 -P9306 -e "SHOW TABLES;" mysql -h127.0.0.1 -P9306 -e "SHOW STATUS;" ``` `SHOW TABLES` lists every index Manticore currently knows about (both the ones from `sphinx.conf` and any created live over SphinxQL). `SHOW STATUS` reports uptime, connections, and query counters, useful for confirming the server is actually healthy rather than just "container running." ## Backup and restore Manticore's real-time indexes keep recent writes in memory before they're flushed to disk, so flush before copying files to make sure the backup is complete: ```bash mysql -h127.0.0.1 -P9306 -e "FLUSH RTINDEX testrt;" ``` Repeat for each real-time index you care about (or use `FLUSH RTINDEXES;` in newer versions to flush all of them at once). **Back up** by archiving the data directory on your host, no need to enter the container: ```bash tar -czf manticore-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/manticore" data ``` **Restore** into a fresh container by stopping it, clearing the data folder, extracting your archive back in, then starting again: ```bash ./laradock stop manticore ``` ```bash docker compose stop manticore ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/manticore/data" tar -xzf manticore-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/manticore" ``` ```bash ./laradock start manticore ``` ```bash docker compose up -d manticore ``` ## Start completely fresh (wipe all data) To throw away every index and start Manticore from a clean, empty state (⚠️ this **permanently deletes** all indexed data, back up first if you need anything): ```bash ./laradock stop manticore ./laradock remove manticore rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/manticore/data" ./laradock start manticore ``` ```bash docker compose stop manticore docker compose rm -sf manticore rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/manticore/data" docker compose up -d manticore ``` This only wipes the `data` folder, not `manticore/config/sphinx.conf` (that's a bind-mounted config file, not generated data), so any indexes defined there come back automatically on next start. Indexes you created live over SphinxQL are gone for good since they only ever lived in `data`. ## Talk to this service from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Manticore by container name out of the box. Easiest fix: the ports are already published, have the other project connect to your **host machine's** address instead of `manticore`, for example `host.docker.internal` (Docker Desktop) on this project's `MANTICORE_SPHINXQL_PORT` or `MANTICORE_HTTP_PORT`. Make sure the two projects use different ports if they're both running at once. ## Common issues - **`sphinx.conf` edits don't take effect.** It's bind-mounted, so edits apply after a container restart (`./laradock restart manticore`), no rebuild needed. - **Image drifts over time.** Because the image isn't version-pinned, `./laradock rebuild manticore` can pull a newer Manticore release than you tested against. Pin a tag yourself in `manticore/Dockerfile` if you need reproducibility. - **Port already in use on your host.** Change `MANTICORE_SPHINXQL_PORT`, `MANTICORE_API_PORT`, or `MANTICORE_HTTP_PORT` in `.env` and restart. - **Data not persisting.** Confirm `DATA_PATH_HOST` is set consistently, Manticore's index data and logs live at `DATA_PATH_HOST/manticore/data` and `DATA_PATH_HOST/manticore/log`. - **Writes to a real-time index disappear after a crash.** You skipped the `FLUSH RTINDEX` step above before copying/backing up data, or the container was killed hard enough that recent writes never made it to the binlog. --- Need OLAP analytics instead? See **[ClickHouse](https://laradock.io/docs/services/clickhouse)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # MariaDB Source: https://laradock.io/docs/services/mariadb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MariaDB? [MariaDB](https://mariadb.org) is a community-developed fork of MySQL, created by MySQL's original developers after Oracle's acquisition of MySQL. It's drop-in compatible with MySQL's wire protocol and SQL syntax, so any app that speaks to MySQL (Laravel, WordPress, etc.) works against MariaDB unchanged. Laradock runs it as its own container, pre-wired with sane defaults. ## Start MariaDB ```bash ./laradock start mariadb ``` ```bash docker compose up -d mariadb ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start mariadb workspace`. ## Stop MariaDB Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop mariadb ``` ```bash docker compose stop mariadb ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove mariadb ``` ```bash docker compose rm -sf mariadb ``` ## Configuration All settings live in `mariadb/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `MARIADB_VERSION` | `11.4` | Image tag from [MariaDB's Docker Hub](https://hub.docker.com/_/mariadb). | | `MARIADB_DATABASE` | `default` | Database created automatically on first boot. | | `MARIADB_USER` | `default` | Non-root user created automatically. | | `MARIADB_PASSWORD` | `secret` | Password for `MARIADB_USER`. | | `MARIADB_ROOT_PASSWORD` | `root` | Password for the `root` user. | | `MARIADB_PORT` | `3306` | Host-side port MariaDB is published on (`host:container`). | | `MARIADB_ENTRYPOINT_INITDB` | `./mariadb/docker-entrypoint-initdb.d` | Folder of `.sql`/`.sh` files auto-run on first boot. | ## Change the MariaDB version Set the version in your `.env`: ```env MARIADB_VERSION=10.11 ``` Then apply the change: ```bash ./laradock rebuild mariadb ``` ```bash docker compose build mariadb ``` Changing the **major** version against an existing data folder can break startup (MariaDB doesn't downgrade/cross-upgrade data files cleanly). The safe way to move to a new major version without losing data: 1. **Back up first** (see [Backup and restore](#backup-and-restore) below): `./laradock exec -T mariadb mariadb-dump -uroot -proot default > backup.sql` 2. Set the new `MARIADB_VERSION` in `.env` and [start completely fresh](#start-completely-fresh-wipe-all-data), which wipes `DATA_PATH_HOST/mariadb` and rebuilds on the new version. 3. Restore your backup into the fresh container: `./laradock exec -T mariadb mariadb -uroot -proot default < backup.sql` ## Root access Default root credentials are `root` / `root` (`MARIADB_ROOT_PASSWORD`). Open a terminal inside the MariaDB container, then start the MariaDB prompt: ```bash ./laradock enter mariadb mariadb -uroot -proot ``` ```bash docker compose exec mariadb bash mariadb -uroot -proot ``` For the non-root app user instead: `mariadb -udefault -psecret` (or your own `MARIADB_USER`/`MARIADB_PASSWORD`). ```sql SELECT User FROM mysql.user; SHOW DATABASES; ``` ## Create multiple databases Copy `mariadb/docker-entrypoint-initdb.d/createdb.sql.example` to `createdb.sql` in the same folder, then uncomment/add your statements, following the same pattern MySQL uses: ```sql CREATE DATABASE IF NOT EXISTS `your_db_1` COLLATE 'utf8mb4_general_ci'; GRANT ALL ON `your_db_1`.* TO 'default'@'%'; ``` This file only auto-runs the **first time** the container initializes its data folder (when `DATA_PATH_HOST/mariadb` doesn't exist yet). If your data folder already exists, run it manually instead: ```bash ./laradock enter mariadb mariadb -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ```bash docker compose exec mariadb bash mariadb -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T mariadb mariadb-dump -uroot -proot default > backup.sql ``` ```bash docker compose exec -T mariadb mariadb-dump -uroot -proot default > backup.sql ``` Replace `default` with your database name (`MARIADB_DATABASE`). The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. (`mariadb-dump` is the same tool as `mysqldump`, both ship in the image and work identically.) **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T mariadb mariadb -uroot -proot default < backup.sql ``` ```bash docker compose exec -T mariadb mariadb -uroot -proot default < backup.sql ``` Unlike the `createdb.sql` first-boot init file above, this works anytime, the target database (`default` here) just has to already exist. This is also how you bring in a dump from a client's production site or a MySQL install (MariaDB reads standard MySQL dumps directly). ## Start completely fresh (wipe all data) To throw away everything and start MariaDB from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop mariadb ./laradock remove mariadb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mariadb" ./laradock start mariadb ``` ```bash docker compose stop mariadb docker compose rm -sf mariadb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mariadb" docker compose up -d mariadb ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where MariaDB's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization: `MARIADB_DATABASE`, `MARIADB_USER`, `MARIADB_PASSWORD`, and any `docker-entrypoint-initdb.d` scripts all apply fresh, exactly like a brand-new install. ## Tune server settings `mariadb/my.cnf` is mounted into the container as `/etc/mysql/conf.d/my.cnf`. It ships with `innodb_log_file_size = 4048M` and `innodb_strict_mode = 0`; add any other `[mysqld]` directives there, for example character set/collation: ```conf [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci ``` **`utf8mb4`** (not plain `utf8`) is what you need for full emoji/multi-byte Unicode support, common with WordPress and user-generated content. This only affects **new** databases/tables; existing ones keep their original charset unless you `ALTER` them. Apply the change: ```bash ./laradock restart mariadb ``` ```bash docker compose restart mariadb ``` ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this MariaDB by container name out of the box. Easiest fix: publish the port (already done, `MARIADB_PORT`) and have the other project connect to your **host machine's** address instead of `mariadb`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `MARIADB_PORT`. Make sure the two projects use different `MARIADB_PORT` values if they're both running at once. ## Connect from your host machine Inside Laradock, other containers reach MariaDB by container name: `DB_HOST=mariadb`. From your own machine (a GUI client like TablePlus, DBeaver, or Sequel Ace), connect to `localhost` on `MARIADB_PORT` (`3306` by default) with the credentials above. ## Common issues - **"Access denied" right after first boot.** The container needs a few seconds to initialize on a truly fresh `DATA_PATH_HOST`. Run `./laradock logs mariadb` and wait for a ready message before connecting. - **Credential/database changes don't take effect.** `MARIADB_DATABASE`, `MARIADB_USER`, and `MARIADB_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually after `./laradock enter mariadb`. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same MariaDB data on disk. - **Port already in use on your host.** Another local MySQL/MariaDB (or another Laradock project) is already bound to `3306`. Change `MARIADB_PORT` in `.env` and restart: `./laradock restart mariadb`. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=mariadb` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Running both `mysql` and `mariadb` at once.** They both default to host port `3306`; give one a different `MARIADB_PORT`/`MYSQL_PORT` if you need both up simultaneously. --- Need the original MySQL instead? See **[MySQL](https://laradock.io/docs/services/mysql)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Mongo WebUI Source: https://laradock.io/docs/services/mongo-webui ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mongo WebUI? Mongo WebUI is a browser-based admin interface for MongoDB (built on the [mongoclient](https://github.com/mongoclient/mongoclient) project), letting you browse databases, collections, and documents without installing a desktop GUI. In Laradock it's a thin companion container that talks to the `mongo` service over the internal Docker network. ## Start Mongo WebUI ```bash ./laradock start mongo-webui ``` ```bash docker compose up -d mongo-webui ``` `compose.yml` declares `depends_on: mongo`, so Docker Compose starts the `mongo` container automatically if it isn't already running. ## Stop Mongo WebUI Stopping just pauses the container; its own settings are safe: ```bash ./laradock stop mongo-webui ``` ```bash docker compose stop mongo-webui ``` To delete the container entirely (its data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove mongo-webui ``` ```bash docker compose rm -sf mongo-webui ``` ## Configuration All settings live in `mongo-webui/defaults.env`: | Variable | Default | What it does | |---|---|---| | `MONGO_WEBUI_PORT` | `3000` | Host-side port the UI is published on (`host:container`). | | `MONGO_WEBUI_ROOT_URL` | `http://localhost` | Root URL the UI reports itself as running at. | | `MONGO_WEBUI_MONGO_URL` | `mongodb://mongo:27017/` | Connection string the UI uses to reach the `mongo` container by name. | | `MONGO_WEBUI_INSTALL_MONGO` | `false` | Whether the image should bundle and manage its own embedded MongoDB instance instead of connecting to an external one. | ## Access the UI With both `mongo` and `mongo-webui` running, open [http://localhost:3000](http://localhost:3000) (or your `MONGO_WEBUI_PORT`). The first time you open it you'll be asked to create an account for the UI itself, this login is separate from any MongoDB credentials and is stored in Mongo WebUI's own data (see [Configuration](#configuration) and the volume below), not in the `mongo` container. If authentication is enabled on the `mongo` instance you're connecting to, you'll also need its `MONGO_USERNAME`/`MONGO_PASSWORD` (from `mongo/defaults.env`) once inside. ## Point it at a different Mongo instance By default `MONGO_WEBUI_MONGO_URL` targets Laradock's own `mongo` service by container name. To browse a different MongoDB instance (a remote server, or one outside Laradock), override `MONGO_WEBUI_MONGO_URL` in `.env` with its full connection string, then restart: ```bash ./laradock restart mongo-webui ``` ```bash docker compose restart mongo-webui ``` ## Reset Mongo WebUI's own data `compose.yml` mounts `${DATA_PATH_HOST}/mongo-webui` to `/data/db`, that's where Mongo WebUI keeps its **own** app state (your login account, saved connections), separate from any actual MongoDB data (which lives in the `mongo` service's own volume, untouched by any of this). If you're locked out of the UI or just want a clean slate for it: ```bash ./laradock stop mongo-webui ./laradock remove mongo-webui rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mongo-webui" ./laradock start mongo-webui ``` ```bash docker compose stop mongo-webui docker compose rm -sf mongo-webui rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mongo-webui" docker compose up -d mongo-webui ``` This re-runs first-boot setup, so you'll be prompted to create the UI login again on next visit. Your actual MongoDB databases and collections are unaffected either way. ## Common issues - **Blank page or connection error on load.** Make sure `mongo` is actually up (`docker compose ps mongo`), Mongo WebUI depends on it but a slow first boot of Mongo can still leave the UI briefly unable to connect. - **Can't reach it from another machine.** `MONGO_WEBUI_ROOT_URL` defaults to `http://localhost`; if you're accessing it from another host, adjust accordingly and `./laradock restart mongo-webui`. - **Port already in use on your host.** Another local service is bound to `3000`. Change `MONGO_WEBUI_PORT` in `.env` and `./laradock restart mongo-webui`. - **Wrong data shows up.** Double check `MONGO_WEBUI_MONGO_URL` isn't still pointing at a stale or unintended Mongo instance after switching projects. - **Locked out of the UI itself.** That's the UI's own login, not a MongoDB credential, see [Reset Mongo WebUI's own data](#reset-mongo-webuis-own-data) above. --- Need the database itself, not just the UI? See **[MongoDB](https://laradock.io/docs/services/mongo)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MongoDB Source: https://laradock.io/docs/services/mongo ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MongoDB? [MongoDB](https://www.mongodb.com) is a document-oriented NoSQL database that stores data as flexible, JSON-like documents instead of rows and tables. It's a common choice for apps with unstructured or rapidly evolving schemas. Laradock runs it as its own container. ## Start MongoDB ```bash ./laradock start mongo ``` ```bash docker compose up -d mongo ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start mongo redis`. ## Stop MongoDB Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop mongo ``` ```bash docker compose stop mongo ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`), run `./laradock remove mongo`. ## Configuration All settings live in `mongo/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `MONGODB_PORT` | `27017` | Host-side port MongoDB is published on (`host:container`). | | `MONGO_USERNAME` | `root` | Root user created automatically on first boot (`MONGO_INITDB_ROOT_USERNAME`). | | `MONGO_PASSWORD` | `example` | Password for the root user (`MONGO_INITDB_ROOT_PASSWORD`). | Data persists under `DATA_PATH_HOST/mongo` (database files) and `DATA_PATH_HOST/mongo_config` (config db). ## Change the MongoDB version Unlike most databases in Laradock, MongoDB has no `MONGO_VERSION` env var, the image tag is fixed in `mongo/Dockerfile` (`FROM mongo:latest`). To pin a specific version, edit that line yourself, for example: ```dockerfile FROM mongo:7.0 ``` Then apply the change: ```bash ./laradock rebuild mongo ``` ```bash docker compose build mongo ``` As with any database, jumping major versions against an existing data folder can be risky. Back up first (see [Backup and restore](#backup-and-restore)) before changing versions on a database you care about. ## Root access Open a terminal inside the MongoDB container, then start the Mongo shell as the root user: ```bash ./laradock enter mongo mongosh -u root -p example --authenticationDatabase admin ``` ```bash docker compose exec mongo bash mongosh -u root -p example --authenticationDatabase admin ``` Swap `root` / `example` for your own `MONGO_USERNAME` / `MONGO_PASSWORD` if you changed them. ```js show dbs use database show collections ``` ## Backup and restore **Export (back up) all databases** to an archive file on your host: ```bash ./laradock exec -T mongo mongodump --username root --password example --authenticationDatabase admin --archive > backup.archive ``` ```bash docker compose exec -T mongo mongodump --username root --password example --authenticationDatabase admin --archive > backup.archive ``` Replace the username/password with your own `MONGO_USERNAME`/`MONGO_PASSWORD`. The `-T` disables the container's pseudo-terminal so the archive isn't corrupted when redirected to a file, always include it when piping output to or from a file. Add `--db=your_database` to dump just one database instead of all of them. **Restore (import) an archive** back into the container: ```bash ./laradock exec -T mongo mongorestore --username root --password example --authenticationDatabase admin --archive < backup.archive ``` ```bash docker compose exec -T mongo mongorestore --username root --password example --authenticationDatabase admin --archive < backup.archive ``` This works anytime, the container just has to already be running. It's also how you bring in a dump from a client's production cluster or your previous local MongoDB install. ## Start completely fresh (wipe all data) To throw away everything and start MongoDB from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop mongo ./laradock remove mongo rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mongo" "${DATA_PATH_HOST:-~/.laradock/data}/mongo_config" ./laradock start mongo ``` ```bash docker compose stop mongo docker compose rm -sf mongo rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mongo" "${DATA_PATH_HOST:-~/.laradock/data}/mongo_config" docker compose up -d mongo ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the two folders above are where MongoDB's data files and config db actually live on your machine. Deleting them and starting again re-runs first-boot initialization: `MONGO_USERNAME` and `MONGO_PASSWORD` apply fresh, exactly like a brand-new install. ## Use MongoDB from Laravel 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_MONGO` - `PHP_FPM_INSTALL_MONGO` 2. Rebuild the containers that need the PHP MongoDB driver: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` 3. Start the database container (if it isn't already running): ```bash ./laradock start mongo ``` ```bash docker compose up -d mongo ``` 4. Add a MongoDB connection to `config/database.php`: ```php 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', 27017), 'database' => env('DB_DATABASE', 'database'), 'username' => '', 'password' => '', 'options' => [ 'database' => '', ] ], // ... ], ``` 5. In your Laravel `.env`, set `DB_HOST=mongo`, `DB_PORT=27017`, and `DB_DATABASE=database`. 6. Install the Laravel MongoDB package (formerly `jenssegers/mongodb`, now maintained as [`mongodb/laravel-mongodb`](https://github.com/mongodb/laravel-mongodb)): ```bash composer require mongodb/laravel-mongodb ``` 7. Extend your models from the MongoDB Eloquent model, enter the Workspace, and run `php artisan migrate`. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this MongoDB by container name out of the box. Easiest fix: publish the port (already done, `MONGODB_PORT`) and have the other project connect to your **host machine's** address instead of `mongo`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `MONGODB_PORT`. Make sure the two projects use different `MONGODB_PORT` values if they're both running at once. ## Connect from your host machine Inside Laradock, other containers reach MongoDB by container name: `DB_HOST=mongo`. From your own machine, connect a GUI client (Compass, Studio 3T) to `localhost` on `MONGODB_PORT` (`27017` by default) using `MONGO_USERNAME`/`MONGO_PASSWORD`. Want a browser-based admin UI instead of a desktop client? See **[Mongo WebUI](https://laradock.io/docs/services/mongo-webui)**. ## Common issues - **Auth fails right after first boot.** `MONGO_USERNAME`/`MONGO_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user manually via the Mongo shell. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=mongo` (the container name), not `localhost`, which only works from your host machine. - **Driver not found in PHP.** The Mongo PHP extension isn't installed by default, you must set `WORKSPACE_INSTALL_MONGO` and `PHP_FPM_INSTALL_MONGO` to `true` and rebuild before `composer require mongodb/laravel-mongodb` will work. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same MongoDB data on disk. - **Port already in use on your host.** Another local MongoDB (or another Laradock project) is already bound to `27017`. Change `MONGODB_PORT` in `.env` and restart: `./laradock restart mongo`. --- Need a graph database instead? See **[Neo4j](https://laradock.io/docs/services/neo4j)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # SQL Server (MSSQL) Source: https://laradock.io/docs/services/mssql ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is SQL Server? [Microsoft SQL Server](https://www.microsoft.com/sql-server) is Microsoft's relational database engine. Laradock runs the Linux-based [`mssql/server` image](https://hub.docker.com/_/microsoft-mssql-server) on the free Express edition, useful when your app needs to talk to SQL Server specifically (legacy systems, enterprise integrations, `sqlsrv`/`pdo_sqlsrv` PHP drivers). ## Start SQL Server ```bash ./laradock start mssql ``` ```bash docker compose up -d mssql ``` It runs as its own container with no `depends_on` in `compose.yml`. Name any other services alongside it to start them together, for example `./laradock start mssql redis`. ## Stop SQL Server Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop mssql ``` ```bash docker compose stop mssql ``` To delete the container entirely (the data is still untouched, it lives in the named Docker volume `mssql`, not `DATA_PATH_HOST` like most other Laradock databases): ```bash ./laradock remove mssql ``` ```bash docker compose rm -sf mssql ``` ## Configuration All settings live in `mssql/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `MSSQL_DATABASE` | `master` | Database name passed to the container. | | `MSSQL_PASSWORD` | `"yourStrong(!)Password"` | Password for the `sa` (system administrator) login (mapped to `SA_PASSWORD`). Change this, it's a well-known default. | | `MSSQL_PORT` | `1433` | Host-side port SQL Server is published on (`host:container`). | `compose.yml` also hardcodes `MSSQL_PID=Express` (the free Express edition) and `ACCEPT_EULA=Y`, meaning **by using this container you're accepting Microsoft's SQL Server EULA** on your behalf; review the [SQL Server licensing terms](https://www.microsoft.com/en-us/sql-server/sql-server-2022-pricing) if that matters for your use case. ## Connect with sqlcmd Open a terminal inside the container, then start `sqlcmd`: ```bash ./laradock enter mssql ``` ```bash docker compose exec mssql bash ``` ```bash /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'yourStrong(!)Password' ``` Use your own `MSSQL_PASSWORD` if you changed it. `/opt/mssql-tools` may live at a different path depending on the image version, check with `find / -iname sqlcmd` inside the container if the above path doesn't exist. ## Connect from your host machine Inside Laradock, other containers reach SQL Server by container name: `DB_HOST=mssql`. From your own machine (Azure Data Studio, DBeaver, TablePlus), connect to `localhost` on `MSSQL_PORT` (`1433` by default) with user `sa` and `MSSQL_PASSWORD`. ## Backup and restore Because SQL Server's data lives in a named Docker volume rather than a `DATA_PATH_HOST` bind mount, backups go through `sqlcmd`'s own `BACKUP`/`RESTORE` commands plus `docker compose cp` to move the file to and from your host. **Back up** the database to a `.bak` file inside the container, then copy it out: ```bash ./laradock exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'yourStrong(!)Password' -Q "BACKUP DATABASE [master] TO DISK = N'/var/opt/mssql/data/backup.bak'" ``` ```bash docker compose exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'yourStrong(!)Password' -Q "BACKUP DATABASE [master] TO DISK = N'/var/opt/mssql/data/backup.bak'" ``` ```bash docker compose cp mssql:/var/opt/mssql/data/backup.bak ./backup.bak ``` Replace `master` with your database name (`MSSQL_DATABASE`). `docker compose cp` works regardless of which tab you use above, it isn't a per-service command. **Restore** a `.bak` file: copy it into the container, then run `RESTORE DATABASE`: ```bash docker compose cp ./backup.bak mssql:/var/opt/mssql/data/backup.bak ``` ```bash ./laradock exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'yourStrong(!)Password' -Q "RESTORE DATABASE [master] FROM DISK = N'/var/opt/mssql/data/backup.bak' WITH REPLACE" ``` ```bash docker compose exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'yourStrong(!)Password' -Q "RESTORE DATABASE [master] FROM DISK = N'/var/opt/mssql/data/backup.bak' WITH REPLACE" ``` `WITH REPLACE` overwrites the existing database of that name, drop it if you're restoring into a database that doesn't exist yet. ## Start completely fresh (wipe all data) To throw away everything and start SQL Server from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop mssql ./laradock remove mssql docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_mssql ./laradock start mssql ``` ```bash docker compose stop mssql docker compose rm -sf mssql docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_mssql docker compose up -d mssql ``` Docker Compose names the volume `_mssql` by default, `COMPOSE_PROJECT_NAME` is whatever you have set in `.env`. Run `docker volume ls | grep mssql` first if you're not sure of the exact name. Deleting the volume and starting again re-runs first-boot initialization, exactly like a brand-new install. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this SQL Server by container name out of the box. Easiest fix: publish the port (already done, `MSSQL_PORT`) and have the other project connect to your **host machine's** address instead of `mssql`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `MSSQL_PORT`. Make sure the two projects use different `MSSQL_PORT` values if they're both running at once. ## Common issues - **Container exits immediately after start.** SQL Server enforces a strong-password policy; if you set `MSSQL_PASSWORD` to something too simple it will refuse to start. Check `./laradock logs mssql` for the exact complaint. - **Weak default password.** `yourStrong(!)Password` is a well-known default from Microsoft's own examples, change `MSSQL_PASSWORD` before using this anywhere beyond a throwaway local environment. - **Data doesn't reset when you expect it to.** Unlike MySQL/Postgres/MariaDB in Laradock, SQL Server's data lives in the named volume `mssql`, not under `DATA_PATH_HOST`. See [Start completely fresh](#start-completely-fresh-wipe-all-data) above to wipe it. - **App can't connect but the container is running.** Confirm the app's config uses `mssql` (the container name), not `localhost`, which only works from your host machine. - **Port already in use on your host.** Another local SQL Server (or another Laradock project) is already bound to `1433`. Change `MSSQL_PORT` in `.env` and restart: `./laradock restart mssql`. --- Need a MySQL-compatible database instead? See **[MySQL](https://laradock.io/docs/services/mysql)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MySQL Source: https://laradock.io/docs/services/mysql ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MySQL? [MySQL](https://www.mysql.com) is the world's most widely used open-source relational database, the default choice for most PHP apps (Laravel, WordPress, and most of the frameworks and CMSs Laradock supports ship with MySQL out of the box). Laradock runs it as its own container, pre-wired with sane defaults, so you never install MySQL on your host machine. ## Start MySQL ```bash ./laradock start mysql ``` ```bash docker compose up -d mysql ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start mysql redis`. ## Stop MySQL Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop mysql ``` ```bash docker compose stop mysql ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove mysql ``` ```bash docker compose rm -sf mysql ``` ## Configuration All settings live in `mysql/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `MYSQL_VERSION` | `8.4` | Image tag from [MySQL's Docker Hub](https://hub.docker.com/_/mysql): `5.7`, `8.0`, `8.4`, `9.0`, `latest`, etc. | | `MYSQL_DATABASE` | `default` | Database created automatically on first boot. | | `MYSQL_USER` | `default` | Non-root user created automatically. | | `MYSQL_PASSWORD` | `secret` | Password for `MYSQL_USER`. | | `MYSQL_ROOT_PASSWORD` | `root` | Password for the `root` user. | | `MYSQL_PORT` | `3306` | Host-side port MySQL is published on (`host:container`). | | `MYSQL_ENTRYPOINT_INITDB` | `./mysql/docker-entrypoint-initdb.d` | Folder of `.sql`/`.sh` files auto-run on first boot. | :::warning Passwords apply on first boot only `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_ROOT_PASSWORD` take effect the first time MySQL starts and creates its data files. Changing them in `.env` later (even with a rebuild) does not touch an existing database; the old password keeps working. Change it inside MySQL instead (`ALTER USER 'default'@'%' IDENTIFIED BY 'newpass';`), or [wipe the data folder](#start-completely-fresh-wipe-all-data) to re-initialize. ::: ## Change the MySQL version Set the version in your `.env`: ```env MYSQL_VERSION=8.0 ``` Then apply the change: ```bash ./laradock rebuild mysql ``` ```bash docker compose build mysql ``` Changing the **major** version against an existing data folder can break startup (MySQL doesn't downgrade/cross-upgrade data files cleanly). The safe way to move to a new major version without losing data: 1. **Back up first** (see [Backup and restore](#backup-and-restore) below): `./laradock exec -T mysql mysqldump -uroot -proot default > backup.sql` 2. Set the new `MYSQL_VERSION` in `.env` and [start completely fresh](#start-completely-fresh-wipe-all-data), which wipes `DATA_PATH_HOST/mysql` and rebuilds on the new version. 3. Restore your backup into the fresh container: `./laradock exec -T mysql mysql -uroot -proot default < backup.sql` ## Root access Default root credentials are `root` / `root` (`MYSQL_ROOT_PASSWORD`). Open a terminal inside the MySQL container, then start the MySQL prompt: ```bash ./laradock enter mysql mysql -uroot -proot ``` ```bash docker compose exec mysql bash mysql -uroot -proot ``` For the non-root app user instead: `mysql -udefault -psecret` (or your own `MYSQL_USER`/`MYSQL_PASSWORD`). ```sql SELECT User FROM mysql.user; SHOW DATABASES; ``` ## Create multiple databases Copy `mysql/docker-entrypoint-initdb.d/createdb.sql.example` to `createdb.sql` in the same folder, then uncomment/add your statements: ```sql CREATE DATABASE IF NOT EXISTS `your_db_1` COLLATE 'utf8mb4_general_ci'; GRANT ALL ON `your_db_1`.* TO 'default'@'%'; ``` This file only auto-runs the **first time** the container initializes its data folder (when `DATA_PATH_HOST/mysql` doesn't exist yet). If your data folder already exists, run it manually instead: ```bash ./laradock enter mysql mysql -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ```bash docker compose exec mysql bash mysql -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T mysql mysqldump -uroot -proot default > backup.sql ``` ```bash docker compose exec -T mysql mysqldump -uroot -proot default > backup.sql ``` Replace `default` with your database name (`MYSQL_DATABASE`). The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T mysql mysql -uroot -proot default < backup.sql ``` ```bash docker compose exec -T mysql mysql -uroot -proot default < backup.sql ``` Unlike the `createdb.sql` first-boot init file above, this works anytime, the target database (`default` here) just has to already exist. This is also how you bring in a dump from a client's production site or your previous local MySQL install. ## Start completely fresh (wipe all data) To throw away everything and start MySQL from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop mysql ./laradock remove mysql rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mysql" ./laradock start mysql ``` ```bash docker compose stop mysql docker compose rm -sf mysql rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mysql" docker compose up -d mysql ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where MySQL's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization: `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD`, and any `docker-entrypoint-initdb.d` scripts all apply fresh, exactly like a brand-new install. ## Character set, collation, and timezone Two common mismatches to fix in `mysql/my.cnf`: ```conf [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci default-time-zone = "+00:00" ``` - **`utf8mb4`** (not plain `utf8`) is what you need for full emoji/multi-byte Unicode support, common with WordPress and user-generated content. - **`default-time-zone`** controls what `NOW()`/`CURRENT_TIMESTAMP` return inside MySQL; set it to match your app (`WORKSPACE_TIMEZONE` in `.env` controls the *container's* OS timezone, this is MySQL's own separate setting). Restart after editing (`./laradock restart mysql`). This only affects **new** databases/tables; existing ones keep their original charset unless you `ALTER` them. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this MySQL by container name out of the box. Easiest fix: publish the port (already done, `MYSQL_PORT`) and have the other project connect to your **host machine's** address instead of `mysql`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `MYSQL_PORT`. Make sure the two projects use different `MYSQL_PORT` values if they're both running at once. ## Change the MySQL port **Container-internal port** (what MySQL listens on inside the container): set in `mysql/my.cnf`. ```conf [mysqld] port=1234 ``` If you also need to reach it from your host on that port, update the mapping in `mysql/compose.yml` (`"3306:3306"` β†’ `"3306:1234"`). **Host-side port** (what you connect to from your machine, container-internal port unchanged): set `MYSQL_PORT` in `.env`, then restart: ```bash ./laradock restart mysql ``` ```bash docker compose restart mysql ``` ## Connect from your host machine Inside Laradock, other containers reach MySQL by container name: `DB_HOST=mysql`. From your own machine (a GUI client like TablePlus, DBeaver, or Sequel Ace), connect to `localhost` on `MYSQL_PORT` (`3306` by default) with the credentials above. ## Common issues - **"Access denied" right after first boot.** The container needs a few seconds to initialize on a truly fresh `DATA_PATH_HOST`. Run `./laradock logs mysql` and wait for `ready for connections` before connecting. - **Credential/database changes don't take effect.** `MYSQL_DATABASE`, `MYSQL_USER`, and `MYSQL_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually after `./laradock enter mysql`. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same MySQL data on disk. - **Port already in use on your host.** Another local MySQL (or another Laradock project) is already bound to `3306`. Change `MYSQL_PORT` in `.env` and restart: `./laradock restart mysql`. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=mysql` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. --- Prefer a GUI over the command line? See **[phpMyAdmin](https://laradock.io/docs/services/phpmyadmin)** or **[Adminer](https://laradock.io/docs/services/adminer)**. Need Postgres or MongoDB instead? See the full **[Databases guide](https://laradock.io/docs/Intro#supported-services)**. ================================================================ # Neo4j Source: https://laradock.io/docs/services/neo4j ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Neo4j? [Neo4j](https://neo4j.com) is a native graph database: data is stored as nodes and relationships rather than rows or documents, which makes it well-suited for highly connected data (social graphs, recommendation engines, fraud detection). Laradock runs it straight from the [official `neo4j` image](https://hub.docker.com/_/neo4j) with no custom Dockerfile. ## Start Neo4j ```bash ./laradock start neo4j ``` ```bash docker compose up -d neo4j ``` It runs as its own container with no `depends_on` in `compose.yml`. Your data is created on first start and kept between restarts. ## Stop Neo4j Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop neo4j ``` ```bash docker compose stop neo4j ``` Data persists under `DATA_PATH_HOST/neo4j/data`, and logs under `DATA_PATH_HOST/neo4j/logs`. To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove neo4j ``` ```bash docker compose rm -sf neo4j ``` ## Configuration There is no `neo4j/defaults.env` file for this service, everything is hardcoded directly in `neo4j/compose.yml`: | Setting | Value | What it does | |---|---|---| | Image | `neo4j:latest` | Not version-pinned or overridable via `.env`; edit `compose.yml` directly to change it. | | `NEO4J_AUTH` | `none` | Authentication is disabled entirely, no username/password is required to connect. | | Host port `7401` | β†’ container `7474` | Neo4j Browser (HTTP UI). | | Host port `7402` | β†’ container `7687` | Bolt protocol port, used by drivers/apps. | If you need a pinned version, authentication enabled, or different ports, you'll need to edit `neo4j/compose.yml` yourself, there's currently no `.env`-driven way to change these. ## Open the Neo4j Browser With the container running, open [http://localhost:7401](http://localhost:7401). Since `NEO4J_AUTH=none`, you can connect without entering credentials. ## Run Cypher from the command line Open a terminal inside the container, then start `cypher-shell`: ```bash ./laradock enter neo4j ``` ```bash docker compose exec neo4j bash ``` ```bash cypher-shell ``` With `NEO4J_AUTH=none` no username/password is needed. Once authentication is enabled (see below), connect with `cypher-shell -u neo4j -p yourpassword` instead. ## Enable authentication The default `NEO4J_AUTH=none` means **anyone who can reach the port has full read/write access to your graph**, fine for local dev, not something to carry into anything less trusted. To turn it on, edit the `environment:` block in `neo4j/compose.yml`: ```yaml environment: - NEO4J_AUTH=neo4j/yourpassword ``` Neo4j requires passwords to be at least 8 characters. Apply the change: ```bash ./laradock restart neo4j ``` ```bash docker compose restart neo4j ``` This only takes effect on a **fresh** data folder; if `DATA_PATH_HOST/neo4j/data` already exists from a previous `NEO4J_AUTH=none` run, either [start completely fresh](#start-completely-fresh-wipe-all-data) or set the password for the existing `neo4j` user from inside `cypher-shell`: ```cypher ALTER CURRENT USER SET PASSWORD FROM 'neo4j' TO 'yourpassword'; ``` ## Connect from your app Use the Bolt protocol on the mapped port: `bolt://localhost:7402` from your host machine, or `bolt://neo4j:7687` from inside another Laradock container. ## Backup and restore Neo4j's data lives entirely in the bind-mounted `DATA_PATH_HOST/neo4j/data` folder on your host, so the reliable way to back it up is a plain file copy while the container is stopped (avoids copying files mid-write): ```bash ./laradock stop neo4j ``` ```bash docker compose stop neo4j ``` ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/data" ~/neo4j-backup-$(date +%Y%m%d) ``` Start it back up once the copy finishes: ```bash ./laradock start neo4j ``` ```bash docker compose up -d neo4j ``` **To restore**, stop the container, replace the contents of `DATA_PATH_HOST/neo4j/data` with your backup, and start it again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/data" cp -r ~/neo4j-backup-YYYYMMDD "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/data" ``` Then `./laradock start neo4j` (or the Docker Compose equivalent above). ## Start completely fresh (wipe all data) To throw away your graph entirely and start Neo4j from a clean, empty state (⚠️ this **permanently deletes** every node, relationship, and index, back up first if you need anything): ```bash ./laradock stop neo4j ./laradock remove neo4j rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/data" "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/logs" ./laradock start neo4j ``` ```bash docker compose stop neo4j docker compose rm -sf neo4j rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/data" "${DATA_PATH_HOST:-~/.laradock/data}/neo4j/logs" docker compose up -d neo4j ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folders above are where Neo4j's data and logs actually live on your machine. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Neo4j by container name out of the box. Easiest fix: the ports are already published (`7401`/`7402`), so have the other project connect to your **host machine's** address instead of `neo4j`, for example `bolt://host.docker.internal:7402` (Docker Desktop). Make sure the two projects use different host ports if they're both running at once, there's no `.env` variable for these yet, edit the `ports:` mapping in `neo4j/compose.yml` directly. ## Common issues - **No authentication by default.** `NEO4J_AUTH=none` means anyone who can reach the port has full access. See [Enable authentication](#enable-authentication) above before exposing it anywhere less trusted. - **Can't change the version via `.env`.** Unlike most other Laradock services, the Neo4j image tag isn't parameterized, edit the `image:` line in `neo4j/compose.yml` directly and run `./laradock rebuild neo4j` afterward. - **Port already in use on your host.** Another service is bound to `7401` or `7402`. Edit the port mapping in `neo4j/compose.yml` since there's no env var for it. - **App can't connect but the container is running.** Confirm the app's config uses `neo4j` (the container name) and port `7687` from inside other Laradock containers, not `localhost`, which only works from your host machine. - **`cypher-shell` asks for credentials after enabling auth.** Once you set `NEO4J_AUTH=neo4j/yourpassword`, every connection (Browser, `cypher-shell`, drivers) needs that username/password, there's no partial-auth mode. --- Need a wide-column store instead? See **[Cassandra](https://laradock.io/docs/services/cassandra)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Percona Server Source: https://laradock.io/docs/services/percona ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Percona Server? [Percona Server](https://www.percona.com/software/mysql-database/percona-server) is a free, open-source, performance-focused fork of MySQL, drop-in compatible with MySQL's protocol and SQL syntax but with additional enterprise-grade features (extra performance metrics, XtraDB storage engine improvements) built in. Laradock runs it pinned to Percona `8.0`. ## Start Percona ```bash ./laradock start percona ``` ```bash docker compose up -d percona ``` It runs as its own container with no `depends_on` in `compose.yml`. Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start percona redis`. ## Stop Percona Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop percona ``` ```bash docker compose stop percona ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove percona ``` ```bash docker compose rm -sf percona ``` ## Configuration All settings live in `percona/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `PERCONA_DATABASE` | `homestead` | Database created automatically on first boot. | | `PERCONA_USER` | `homestead` | Non-root user created automatically. | | `PERCONA_PASSWORD` | `secret` | Password for `PERCONA_USER`. | | `PERCONA_ROOT_PASSWORD` | `root` | Password for the `root` user. | | `PERCONA_PORT` | `3306` | Host-side port Percona is published on (`host:container`). | | `PERCONA_ENTRYPOINT_INITDB` | `./percona/docker-entrypoint-initdb.d` | Folder of `.sql`/`.sh` files auto-run on first boot. | Unlike Laradock's other MySQL-family services, `percona/Dockerfile` pins the image to `percona:8.0` directly rather than exposing a version build arg, so there's no `PERCONA_VERSION` variable to override. To move to a different Percona major version you'd need to edit `percona/Dockerfile` yourself, and the same data-compatibility caution as MySQL applies: back up first, then [start completely fresh](#start-completely-fresh-wipe-all-data) on the new image. ## Root access Default root credentials are `root` / `root` (`PERCONA_ROOT_PASSWORD`). Open a terminal inside the Percona container, then start the MySQL-compatible prompt: ```bash ./laradock enter percona mysql -uroot -proot ``` ```bash docker compose exec percona bash mysql -uroot -proot ``` For the non-root app user instead: `mysql -uhomestead -psecret` (or your own `PERCONA_USER`/`PERCONA_PASSWORD`). ```sql SELECT User FROM mysql.user; SHOW DATABASES; ``` ## Create multiple databases Copy `percona/docker-entrypoint-initdb.d/createdb.sql.example` to `createdb.sql` in the same folder, then uncomment/add your statements, following the same pattern MySQL uses: ```sql CREATE DATABASE IF NOT EXISTS `your_db_1` COLLATE 'utf8mb4_general_ci'; GRANT ALL ON `your_db_1`.* TO 'homestead'@'%'; ``` This file only auto-runs the **first time** the container initializes its data folder (when `DATA_PATH_HOST/percona` doesn't exist yet). If your data folder already exists, run it manually instead: ```bash ./laradock enter percona mysql -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ```bash docker compose exec percona bash mysql -uroot -proot < /docker-entrypoint-initdb.d/createdb.sql ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T percona mysqldump -uroot -proot homestead > backup.sql ``` ```bash docker compose exec -T percona mysqldump -uroot -proot homestead > backup.sql ``` Replace `homestead` with your database name (`PERCONA_DATABASE`). The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T percona mysql -uroot -proot homestead < backup.sql ``` ```bash docker compose exec -T percona mysql -uroot -proot homestead < backup.sql ``` Unlike the `createdb.sql` first-boot init file above, this works anytime, the target database (`homestead` here) just has to already exist. This is also how you bring in a dump from MySQL or another Percona install, since the wire protocol and SQL dialect are compatible. ## Start completely fresh (wipe all data) To throw away everything and start Percona from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop percona ./laradock remove percona rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/percona" ./laradock start percona ``` ```bash docker compose stop percona docker compose rm -sf percona rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/percona" docker compose up -d percona ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Percona's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization: `PERCONA_DATABASE`, `PERCONA_USER`, `PERCONA_PASSWORD`, and any `docker-entrypoint-initdb.d` scripts all apply fresh, exactly like a brand-new install. ## Tune server settings `percona/my.cnf` is copied into the image at build time (`/etc/mysql/conf.d/my.cnf` via the `Dockerfile`, not a live volume mount), so changes need a rebuild to take effect. It ships with a strict `sql-mode` (`STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION`); add any other `[mysqld]` directives there, then apply: ```bash ./laradock rebuild percona ``` ```bash docker compose build percona ``` ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Percona by container name out of the box. Easiest fix: publish the port (already done, `PERCONA_PORT`) and have the other project connect to your **host machine's** address instead of `percona`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `PERCONA_PORT`. Make sure the two projects use different `PERCONA_PORT` values if they're both running at once. ## Connect from your host machine Inside Laradock, other containers reach Percona by container name: `DB_HOST=percona`. From your own machine (a GUI client like TablePlus, DBeaver, or Sequel Ace), connect to `localhost` on `PERCONA_PORT` (`3306` by default) with the credentials above. ## Common issues - **"Access denied" right after first boot.** The container needs a few seconds to initialize on a truly fresh `DATA_PATH_HOST`. Run `./laradock logs percona` and wait for a ready message before connecting. - **Credential/database changes don't take effect.** `PERCONA_DATABASE`, `PERCONA_USER`, and `PERCONA_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually after `./laradock enter percona`. - **`my.cnf` edits don't seem to apply.** `percona/my.cnf` is baked into the image at build time, not volume-mounted. `./laradock restart percona` alone won't pick up changes, you need `./laradock rebuild percona` first. - **Running alongside `mysql` or `mariadb`.** They all default to host port `3306`; give each a distinct `PERCONA_PORT`/`MYSQL_PORT`/`MARIADB_PORT` if you need more than one up simultaneously. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same Percona data on disk. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=percona` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. --- Need the community MySQL build instead? See **[MySQL](https://laradock.io/docs/services/mysql)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # pgAdmin Source: https://laradock.io/docs/services/pgadmin ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is pgAdmin? [pgAdmin](https://www.pgadmin.org) is the standard web-based admin GUI for PostgreSQL, browse schemas, run queries, manage roles, and inspect query plans. There's nothing to "install", Laradock runs it straight from the official `dpage/pgadmin4` image and points it at your `postgres` container. ## Start pgAdmin pgAdmin is useless without a Postgres server to point at, so start both together: ```bash ./laradock start postgres pgadmin ``` ```bash docker compose up -d postgres pgadmin ``` `pgadmin` depends on `postgres` in `pgadmin/compose.yml`, so Compose starts `postgres` first automatically even if you just start `pgadmin` on its own. ## Stop pgAdmin ```bash ./laradock stop pgadmin ``` ```bash docker compose stop pgadmin ``` This stops the container without deleting its saved server list. Data lives under `DATA_PATH_HOST/pgadmin`. To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove pgadmin ``` ```bash docker compose rm -sf pgadmin ``` ## Configuration All settings live in `pgadmin/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `PGADMIN_PORT` | `5050` | Host-side port for the web UI (container port `80`). | | `PGADMIN_DEFAULT_EMAIL` | `pgadmin4@pgadmin.org` | Login email for the pgAdmin app itself (not a Postgres credential). | | `PGADMIN_DEFAULT_PASSWORD` | `admin` | Login password for the pgAdmin app itself. | ## Log in Open [http://localhost:5050](http://localhost:5050) and sign in with `PGADMIN_DEFAULT_EMAIL` / `PGADMIN_DEFAULT_PASSWORD` (`pgadmin4@pgadmin.org` / `admin` by default). ## Connect to your Postgres server Once logged in, add a new server in pgAdmin's UI: - **Host**: `postgres` (the container name) - **Port**: `5432` (container-internal port) - **Username/Password**: your `POSTGRES_USER`/`POSTGRES_PASSWORD` (`default`/`secret` by default) pgAdmin remembers this server definition in its own storage (`DATA_PATH_HOST/pgadmin`), so you only need to add it once, it's still there next time you log in. ## Reset pgAdmin (forget saved servers and login) To wipe pgAdmin's own storage, saved server list, app login, preferences, without touching your actual Postgres data: ```bash ./laradock stop pgadmin ``` ```bash docker compose stop pgadmin ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/pgadmin" ``` ```bash ./laradock start pgadmin ``` ```bash docker compose up -d pgadmin ``` The next start re-applies `PGADMIN_DEFAULT_EMAIL`/`PGADMIN_DEFAULT_PASSWORD` as if it were a brand-new install, and you'll need to re-add your Postgres server connection. Your actual databases (in the `postgres` container's own `DATA_PATH_HOST/postgres` volume) are completely unaffected. ## Common issues - **pgAdmin login and Postgres login are different things.** `PGADMIN_DEFAULT_EMAIL`/`PGADMIN_DEFAULT_PASSWORD` only get you into the pgAdmin app itself, you still add and authenticate against your actual Postgres server separately inside the UI. - **Credential changes don't take effect.** `PGADMIN_DEFAULT_EMAIL`/`PGADMIN_DEFAULT_PASSWORD` are only applied when `DATA_PATH_HOST/pgadmin` is created for the first time. If you change them afterward, either [reset pgAdmin](#reset-pgadmin-forget-saved-servers-and-login) (loses saved servers/settings, Postgres data is untouched) or change the user from inside pgAdmin's own user management. - **Can't reach Postgres by container name.** Use `postgres` as the host inside pgAdmin's server dialog, not `localhost`, that only works from your host machine, not from inside another container. - **Port already in use on your host.** Change `PGADMIN_PORT` in `.env` and restart: `./laradock restart pgadmin`. - **"Unable to connect to server" right after first boot.** Postgres needs a few seconds to initialize on a truly fresh `DATA_PATH_HOST`. Run `./laradock logs postgres` and wait for `database system is ready to accept connections` before adding the server in pgAdmin. --- Need a MySQL/MariaDB GUI instead? See **[phpMyAdmin](https://laradock.io/docs/services/phpmyadmin)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # pgbackups Source: https://laradock.io/docs/services/pgbackups ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is pgbackups? `pgbackups` is a companion sidecar container that takes scheduled, automatic backups of the [`postgres`](https://laradock.io/docs/services/postgres) service, built on [prodrigestivill/postgres-backup-local](https://github.com/prodrigestivill/docker-postgres-backup-local). It doesn't run a database of its own, it connects to your existing `postgres` container and dumps it on a schedule. ## Start pgbackups ```bash ./laradock start pgbackups ``` ```bash docker compose up -d pgbackups ``` Make sure `postgres` is running too, `pgbackups` links to it and has nothing to back up otherwise: ```bash ./laradock start postgres pgbackups ``` ```bash docker compose up -d postgres pgbackups ``` ## Stop pgbackups Stopping just pauses the scheduled backups, backups already written to `../backup` are untouched: ```bash ./laradock stop pgbackups ``` ```bash docker compose stop pgbackups ``` To delete the container entirely (existing backups on disk are still untouched, they live under `../backup`): ```bash ./laradock remove pgbackups ``` ```bash docker compose rm -sf pgbackups ``` ## Configuration `pgbackups` has no `defaults.env` of its own. Its `environment:` block in `pgbackups/compose.yml` reuses the same variables as the `postgres` service, defined at the repo root in `.env.example`: | Variable | Default | What it does | |---|---|---| | `POSTGRES_DB` | `default` | Database dumped on each backup run. | | `POSTGRES_USER` | `default` | User used to connect and run the dump. | | `POSTGRES_PASSWORD` | `secret` | Password for `POSTGRES_USER`. | There's also a `POSTGRES_HOST` line in `pgbackups/compose.yml`, but as shipped it reads `POSTGRES_HOST={POSTGRES_HOST}` (missing the `$` for variable interpolation), so it's passed to the container literally as the string `{POSTGRES_HOST}` rather than being substituted from `.env`. In practice this doesn't break backups because the image's own entrypoint falls back to the linked `postgres` host, but don't rely on setting `POSTGRES_HOST` in `.env` to change it, edit `pgbackups/compose.yml` directly if you need a non-default host. ## Where backups are written ``` ../backup ``` That's one level above your Laradock folder on the host (mounted to `/backups` in the container). Inside it, `postgres-backup-local` organizes dumps into `last/`, `daily/`, `weekly/`, and `monthly/` subfolders, each holding gzip-compressed `.sql.gz` files, so the same backup gets retained at different granularities as it ages. ## Change the schedule or retention The image supports its own environment variables for this (`SCHEDULE`, `BACKUP_KEEP_DAYS`, `BACKUP_KEEP_WEEKS`, `BACKUP_KEEP_MONTHS`, and more, see the [postgres-backup-local docs](https://github.com/prodrigestivill/docker-postgres-backup-local)). None are set by default in `pgbackups/compose.yml`, so the image's own defaults apply (a daily backup, keeping the last 7 daily / 4 weekly / 6 monthly copies). Add the variables you want to override under its `environment:` block, then recreate the container so it picks them up: ```bash ./laradock start pgbackups ``` ```bash docker compose up -d pgbackups ``` ## Trigger a backup on demand Don't want to wait for the schedule? Run the image's own backup script directly inside the running container: ```bash ./laradock exec -T pgbackups /backup.sh ``` ```bash docker compose exec -T pgbackups /backup.sh ``` This runs a dump immediately using the container's current environment, on top of (not instead of) its regular schedule. ## Restore a backup into postgres `pgbackups` only takes backups, it doesn't restore them, restoring is a two-step job that goes through `postgres` directly. First unzip the dump you want on your host: ```bash gunzip -k ../backup/last/default-latest.sql.gz ``` Replace `default` with your `POSTGRES_DB` if you changed it. Then feed the unzipped `.sql` file into `postgres`: ```bash ./laradock exec -T postgres psql -U default -d default < ../backup/last/default-latest.sql ``` ```bash docker compose exec -T postgres psql -U default -d default < ../backup/last/default-latest.sql ``` Replace `default`/`default` with your `POSTGRES_USER`/`POSTGRES_DB` if you changed them from the defaults. The target database has to already exist in `postgres`, this doesn't create it for you. ## Common issues - **No backups appear.** Confirm `postgres` is actually running, `pgbackups` links to it and will keep retrying/failing silently in its logs otherwise. Check with `./laradock logs pgbackups`. - **Wrong credentials in backups.** `pgbackups` reuses `POSTGRES_DB`/`POSTGRES_USER`/`POSTGRES_PASSWORD` from the main `postgres` service. If you changed those for `postgres` after `pgbackups` was already running, restart `pgbackups` to pick up the new values. - **`../backup` folder not found on host.** Docker creates it automatically on first run if it doesn't exist, but confirm you have write access to the parent directory of your Laradock folder. - **Backups exist but you're not sure how fresh they are.** Check `../backup/last/` on your host, it always holds a copy of the most recent successful backup. --- Need the database itself? See the **[Databases guide](https://laradock.io/docs/Intro#supported-services)** for Postgres. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # pgvector Source: https://laradock.io/docs/services/pgvector ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is pgvector? [pgvector](https://github.com/pgvector/pgvector) is a PostgreSQL extension that adds vector similarity search, the standard building block for AI/RAG features (storing and querying embeddings). Laradock runs this as a separate Postgres instance built from the official `pgvector/pgvector` image, with its own port and data folder so it can run alongside the regular [`postgres`](https://laradock.io/docs/services/postgres) service without conflicting. ## Start pgvector ```bash ./laradock start pgvector ``` ```bash docker compose up -d pgvector ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start pgvector workspace`. ## Stop pgvector Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop pgvector ``` ```bash docker compose stop pgvector ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/pgvector`): ```bash ./laradock remove pgvector ``` ```bash docker compose rm -sf pgvector ``` ## Configuration All settings live in `pgvector/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `PGVECTOR_VERSION` | `pg17` | Image tag from [pgvector's Docker Hub image](https://hub.docker.com/r/pgvector/pgvector), matches the underlying Postgres major version. | | `PGVECTOR_PORT` | `5433` | Host-side port (container port `5432`), deliberately different from the regular `postgres` service's `5432` so both can run at once. | | `PGVECTOR_DB` | `default` | Database created automatically on first boot; the `vector` extension is enabled in this database automatically. | | `PGVECTOR_USER` | `default` | Non-root user created automatically. In the upstream Postgres image this user is also the database superuser, there's no separate root account to manage. | | `PGVECTOR_PASSWORD` | `secret` | Password for `PGVECTOR_USER`. | | `PGVECTOR_ENTRYPOINT_INITDB` | `./pgvector/docker-entrypoint-initdb.d` | Folder of init scripts auto-run on first boot, this is where `CREATE EXTENSION vector` happens (`init.sql`). | ## Change the pgvector version Set the version in your `.env`: ```env PGVECTOR_VERSION=pg16 ``` Then apply the change: ```bash ./laradock rebuild pgvector ``` ```bash docker compose build pgvector ``` Changing the **major** Postgres version against an existing data folder can break startup, Postgres doesn't read another major version's data files. The safe way to move to a new major version without losing data: 1. **Back up first** (see [Backup and restore](#backup-and-restore) below): `./laradock exec -T pgvector pg_dump -U default default > backup.sql` 2. Set the new `PGVECTOR_VERSION` in `.env` and [start completely fresh](#start-completely-fresh-wipe-all-data), which wipes `DATA_PATH_HOST/pgvector` and rebuilds on the new version. 3. Restore your backup into the fresh container: `./laradock exec -T pgvector psql -U default -d default -f - < backup.sql` ## Connect from your host machine Connect to `localhost` on `PGVECTOR_PORT` (`5433` by default) with `PGVECTOR_USER`/`PGVECTOR_PASSWORD`, using any Postgres client (psql, TablePlus, DBeaver): ```bash psql -h localhost -p 5433 -U default -d default ``` From another Laradock container, use `DB_HOST=pgvector` and port `5432` (the container-internal port). ## Verify the extension is enabled ```bash ./laradock exec pgvector psql -U default -d default -c "SELECT * FROM pg_extension WHERE extname = 'vector';" ``` ```bash docker compose exec pgvector psql -U default -d default -c "SELECT * FROM pg_extension WHERE extname = 'vector';" ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T pgvector pg_dump -U default default > backup.sql ``` ```bash docker compose exec -T pgvector pg_dump -U default default > backup.sql ``` Replace `default` with your database name (`PGVECTOR_DB`). The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. `pg_dump` includes the stored vector data and the `CREATE EXTENSION vector` statement, so a restore into a fresh database re-enables the extension automatically. **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T pgvector psql -U default -d default -f - < backup.sql ``` ```bash docker compose exec -T pgvector psql -U default -d default -f - < backup.sql ``` The target database (`default` here) just has to already exist. This is also how you bring in a dump from a client's production pgvector instance or a hosted vector DB export. ## Start completely fresh (wipe all data) To throw away everything and start pgvector from a clean, empty state (this **permanently deletes** every database and every stored embedding in this container, back up first if you need anything): ```bash ./laradock stop pgvector ./laradock remove pgvector rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/pgvector" ./laradock start pgvector ``` ```bash docker compose stop pgvector docker compose rm -sf pgvector rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/pgvector" docker compose up -d pgvector ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where pgvector's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization: `PGVECTOR_DB`, `PGVECTOR_USER`, `PGVECTOR_PASSWORD`, and `init.sql` (which re-creates the `vector` extension) all apply fresh, exactly like a brand-new install. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this pgvector by container name out of the box. Easiest fix: publish the port (already done, `PGVECTOR_PORT`) and have the other project connect to your **host machine's** address instead of `pgvector`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `PGVECTOR_PORT`. Make sure the two projects use different `PGVECTOR_PORT` values if they're both running at once. ## Common issues - **`vector` extension missing.** It's enabled by `pgvector/docker-entrypoint-initdb.d/init.sql`, which only runs the **first time** the data folder is created. If you changed `PGVECTOR_DB` after the volume already existed, connect and run `CREATE EXTENSION IF NOT EXISTS vector;` manually. - **Confusing this with the regular `postgres` service.** They're two separate containers with separate ports (`5433` vs `5432`) and separate data folders (`DATA_PATH_HOST/pgvector` vs `DATA_PATH_HOST/postgres`), on purpose, so you can run both. - **Port already in use on your host.** Another local Postgres (or another Laradock project) is already bound to `5433`. Change `PGVECTOR_PORT` in `.env` and restart: `./laradock restart pgvector`. - **App can't connect but the container is running.** From inside another container, the host is `pgvector` and the port is the container-internal `5432`, not `PGVECTOR_PORT`; from your host machine it's the reverse, `localhost` and `PGVECTOR_PORT`. - **Credential/database changes don't take effect.** `PGVECTOR_DB`, `PGVECTOR_USER`, and `PGVECTOR_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually after `./laradock enter pgvector`. --- Need plain Postgres without vectors? See the **[PostgreSQL](https://laradock.io/docs/services/postgres)** page. Back to the **[Databases guide](https://laradock.io/docs/Intro#supported-services)**. ================================================================ # phpMyAdmin Source: https://laradock.io/docs/services/phpmyadmin ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is phpMyAdmin? [phpMyAdmin](https://www.phpmyadmin.net) is a web-based admin GUI for MySQL and MariaDB, browse tables, run queries, manage users, and import/export data without touching a command line. There's nothing to "install", Laradock builds it as its own container from the official `phpmyadmin` image and points it at whichever database container you're already running. ## Start phpMyAdmin phpMyAdmin is useless on its own, it needs a database to point at. Start it alongside the engine set in `PMA_DB_ENGINE` (`mysql` by default): ```bash ./laradock start mysql phpmyadmin ``` ```bash docker compose up -d mysql phpmyadmin ``` With MariaDB instead: ```bash ./laradock start mariadb phpmyadmin ``` ```bash docker compose up -d mariadb phpmyadmin ``` ## Stop phpMyAdmin ```bash ./laradock stop phpmyadmin ``` ```bash docker compose stop phpmyadmin ``` phpMyAdmin itself keeps no data of its own (your actual data lives in the database container it manages), so there's nothing to back up here. To delete the container entirely: ```bash ./laradock remove phpmyadmin ``` ```bash docker compose rm -sf phpmyadmin ``` ## Configuration All settings live in `phpmyadmin/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `PMA_DB_ENGINE` | `mysql` | Which service phpMyAdmin `depends_on` and connects to by default: `mysql` or `mariadb`. | | `PMA_USER` | `default` | Username phpMyAdmin logs in with. | | `PMA_PASSWORD` | `secret` | Password for `PMA_USER`. | | `PMA_ROOT_PASSWORD` | `secret` | Root password passed through to the container. | | `PMA_PORT` | `8081` | Host-side port for the web UI (container port `80`). | | `PMA_MAX_EXECUTION_TIME` | `600` | PHP `max_execution_time`, in seconds, for long-running queries/imports. | | `PMA_MEMORY_LIMIT` | `256M` | PHP `memory_limit` for the container. | | `PMA_UPLOAD_LIMIT` | `2G` | Max upload size, for importing large SQL/CSV files. | ## Log in Open [http://localhost:8081](http://localhost:8081) (or your own `PMA_PORT`). For the default MySQL setup, use server `mysql`, user `default`, password `secret` (or your own `PMA_USER`/`PMA_PASSWORD`). ## Connect to any server, not just the default one Laradock builds phpMyAdmin with `PMA_ARBITRARY=1`, which unlocks the "Server" field on the login screen instead of locking you to `PMA_DB_ENGINE`. Type in any hostname reachable from the container and log in with that server's own credentials, useful for: - Switching between `mysql` and `mariadb` without changing `.env`, as long as both containers are running. - Pointing at a database in a different Laradock project on the same machine, for example `host.docker.internal` with that project's `MYSQL_PORT`. - Pointing at any external MySQL/MariaDB server your Laradock host can reach. ## Switch to MariaDB by default 1. In `.env`, set `PMA_DB_ENGINE=mariadb`. 2. Start `mariadb` instead of `mysql`, see [Start phpMyAdmin](#start-phpmyadmin) above. 3. Log in with server `mariadb`. ## Update to the latest phpMyAdmin version The image is built fresh from the official `phpmyadmin` image with no version pin, so Laradock always uses whatever tag Docker last pulled locally. To force a newer image and rebuild: ```bash ./laradock rebuild phpmyadmin --pull ``` ```bash docker compose build --pull phpmyadmin ``` Then restart it: `./laradock restart phpmyadmin`. ## Common issues - **"mysqli::real_connect(): (HY000/2002)" or similar connection error.** phpMyAdmin `depends_on: ${PMA_DB_ENGINE}`, meaning it starts alongside whichever engine `PMA_DB_ENGINE` names, but if that container isn't actually up (or you changed `PMA_DB_ENGINE` without restarting), the login form has nothing to connect to. Confirm the matching database container is running: `./laradock info`. - **Login rejected.** Double-check `PMA_USER`/`PMA_PASSWORD` match the actual credentials on the target database (`MYSQL_USER`/`MYSQL_PASSWORD` or `MARIADB_USER`/`MARIADB_PASSWORD`), they're independent variables and can drift out of sync if you change one without the other. - **Large import fails partway through.** Raise `PMA_UPLOAD_LIMIT` and `PMA_MAX_EXECUTION_TIME` in `.env`, then restart: `./laradock restart phpmyadmin`. - **Port already in use on your host.** Change `PMA_PORT` in `.env` and restart: `./laradock restart phpmyadmin`. - **Need to log into a server other than the default one.** See [Connect to any server, not just the default one](#connect-to-any-server-not-just-the-default-one) above, `PMA_ARBITRARY=1` is already on. --- Prefer a lighter GUI, or need Postgres/SQLite too? See **[Adminer](https://laradock.io/docs/services/adminer)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # PostgreSQL + PostGIS Source: https://laradock.io/docs/services/postgres-postgis ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is PostgreSQL + PostGIS? [PostGIS](https://postgis.net) is an extension for PostgreSQL that adds support for geographic objects, spatial indexes, and spatial SQL functions (distance, intersection, containment, and more). This service is a full Postgres image with PostGIS already installed, use it instead of plain **[postgres](https://laradock.io/docs/services/postgres)** when your app needs geospatial queries; for everything else the two behave the same. ## Start PostgreSQL + PostGIS ```bash ./laradock start postgres-postgis ``` ```bash docker compose up -d postgres-postgis ``` It runs as its own container and doesn't depend on any other service in `compose.yml`. Note it shares the same connection variables (`POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_PORT`) as the plain `postgres` service, so avoid running both at once unless you give one a different port and data path. ## Stop PostgreSQL + PostGIS Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop postgres-postgis ``` ```bash docker compose stop postgres-postgis ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove postgres-postgis ``` ```bash docker compose rm -sf postgres-postgis ``` ## Configuration | Variable | Default | Where | What it does | |---|---|---|---| | `POSTGIS_VERSION` | `17-3.5` | `postgres-postgis/defaults.env` | Image tag from [postgis/postgis on Docker Hub](https://hub.docker.com/r/postgis/postgis) (Postgres major version + PostGIS version, e.g. `17-3.5`). | | `POSTGIS_INSTALL_PGSQL_HTTP_FOR_POSTGIS13` | `false` | `postgres-postgis/defaults.env` | When `true`, builds and installs the [pgsql-http](https://github.com/pramsey/pgsql-http) extension for making HTTP requests from SQL (only relevant on the PostGIS 13 base image). | | `POSTGRES_DB` | `default` | root `.env` | Database created automatically on first boot. | | `POSTGRES_USER` | `default` | root `.env` | User created automatically on first boot; it's granted superuser rights on this database. | | `POSTGRES_PASSWORD` | `secret` | root `.env` | Password for `POSTGRES_USER`. | | `POSTGRES_PORT` | `5432` | root `.env` | Host-side port published (`host:container`). | Data is stored under `DATA_PATH_HOST/postgres`, the same path plain Postgres uses; running both services against the same `DATA_PATH_HOST` will conflict. ## Change the PostGIS version Set the version in your `.env`: ```env POSTGIS_VERSION=16-3.4 ``` Then apply the change: ```bash ./laradock rebuild postgres-postgis ``` ```bash docker compose build postgres-postgis ``` Changing the **major** Postgres version against an existing data folder can break startup (Postgres doesn't downgrade/cross-upgrade data files cleanly). The safe way to move to a new major version without losing data: 1. **Back up first** (see [Backup and restore](#backup-and-restore) below): `./laradock exec -T postgres-postgis pg_dump -U default default > backup.sql` 2. Set the new `POSTGIS_VERSION` in `.env` and [start completely fresh](#start-completely-fresh-wipe-all-data), which wipes `DATA_PATH_HOST/postgres` and rebuilds on the new version. 3. Restore your backup into the fresh container: `./laradock exec -T postgres-postgis psql -U default default < backup.sql` ## Enable the extension in a database PostGIS ships with the image but each database still needs the extension turned on once: ```bash ./laradock exec postgres-postgis psql -U default -d default -c "CREATE EXTENSION IF NOT EXISTS postgis;" ``` ```bash docker compose exec postgres-postgis psql -U default -d default -c "CREATE EXTENSION IF NOT EXISTS postgis;" ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T postgres-postgis pg_dump -U default default > backup.sql ``` ```bash docker compose exec -T postgres-postgis pg_dump -U default default > backup.sql ``` Replace `default` with your database name (`POSTGRES_DB`) and user. The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T postgres-postgis psql -U default default < backup.sql ``` ```bash docker compose exec -T postgres-postgis psql -U default default < backup.sql ``` The target database (`default` here) must already exist before restoring. This is also how you bring in a dump from a client's production PostGIS database or your previous local install; the destination database still needs `CREATE EXTENSION IF NOT EXISTS postgis;` run once if it wasn't created from an already-spatial dump. ## Start completely fresh (wipe all data) To throw away everything and start PostgreSQL + PostGIS from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop postgres-postgis ./laradock remove postgres-postgis rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/postgres" ./laradock start postgres-postgis ``` ```bash docker compose stop postgres-postgis docker compose rm -sf postgres-postgis rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/postgres" docker compose up -d postgres-postgis ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where the data actually lives on your machine, the same folder plain `postgres` uses. Deleting it and starting again re-runs first-boot initialization: `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` all apply fresh, exactly like a brand-new install, but PostGIS itself is **not** auto-enabled, run [Enable the extension in a database](#enable-the-extension-in-a-database) again afterward. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this database by container name out of the box. Easiest fix: publish the port (already done, `POSTGRES_PORT`) and have the other project connect to your **host machine's** address instead of `postgres-postgis`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `POSTGRES_PORT`. Make sure the two projects use different `POSTGRES_PORT` values if they're both running at once. ## Connect from your host machine Inside Laradock, other containers reach it by container name: `DB_HOST=postgres-postgis`. From your own machine (TablePlus, DBeaver, pgAdmin, QGIS), connect to `localhost` on `POSTGRES_PORT` (`5432` by default) with the credentials above. ## Common issues - **Running `postgres` and `postgres-postgis` together.** Both default to the same `DATA_PATH_HOST/postgres` folder and the same `POSTGRES_PORT`. Pick one, or override `DATA_PATH_HOST`/`POSTGRES_PORT` for whichever you run second. - **`CREATE EXTENSION postgis` fails.** Make sure you're connecting to a database created after the container booted with the PostGIS image; extensions are per-database and must be created explicitly, they aren't automatic, and wiping the data folder (see above) resets this too. - **Credential/database changes don't take effect.** `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` only apply the first time the data folder is created. [Start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually with `./laradock enter postgres-postgis`. - **Port already in use on your host.** Another local Postgres (or another Laradock project) is already bound to `5432`. Change `POSTGRES_PORT` in `.env` and restart: `./laradock restart postgres-postgis`. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=postgres-postgis` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. --- Need Postgres without the geospatial extension? See **[PostgreSQL](https://laradock.io/docs/services/postgres)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # PostgreSQL Source: https://laradock.io/docs/services/postgres ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is PostgreSQL? [PostgreSQL](https://www.postgresql.org) is a powerful open-source object-relational database known for standards compliance, extensibility, and strong support for advanced data types (JSON, arrays, full-text search). It's a common alternative to MySQL for Laravel and other PHP apps. Laradock runs it as its own container, pre-wired with sane defaults. ## Start PostgreSQL ```bash ./laradock start postgres ``` ```bash docker compose up -d postgres ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start postgres workspace`. ## Stop PostgreSQL Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop postgres ``` ```bash docker compose stop postgres ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove postgres ``` ```bash docker compose rm -sf postgres ``` ## Configuration The core connection settings (`POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_PORT`) live in the root `.env`, not in `postgres/defaults.env`, because other services (GitLab, Keycloak, SonarQube, Confluence) share the same Postgres container. `postgres/defaults.env` holds the Postgres-specific settings: | Variable | Default | Where | What it does | |---|---|---|---| | `POSTGRES_VERSION` | `17-alpine` | `postgres/defaults.env` | Image tag from [Postgres's Docker Hub](https://hub.docker.com/_/postgres). | | `POSTGRES_ENTRYPOINT_INITDB` | `./postgres/docker-entrypoint-initdb.d` | `postgres/defaults.env` | Folder of `.sql`/`.sh` files auto-run on first boot. | | `POSTGRES_DB` | `default` | root `.env` | Database created automatically on first boot. | | `POSTGRES_USER` | `default` | root `.env` | User created automatically on first boot. | | `POSTGRES_PASSWORD` | `secret` | root `.env` | Password for `POSTGRES_USER`. | | `POSTGRES_PORT` | `5432` | root `.env` | Host-side port Postgres is published on (`host:container`). | `postgres/defaults.env` also carries `CONFLUENCE_POSTGRES_INIT`, `GITLAB_POSTGRES_INIT`, `SONARQUBE_POSTGRES_INIT`, and `KEYCLOAK_POSTGRES_INIT` flags plus their own db/user/password variables; those exist purely so those other services can get their own database seeded inside the same Postgres instance and aren't needed for a plain app database. :::warning Passwords apply on first boot only `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` take effect the first time Postgres starts and creates its data files. Changing them in `.env` later (even with a rebuild) does not touch an existing database; the old password keeps working. Change it inside Postgres instead (`ALTER USER "default" WITH PASSWORD 'newpass';`), or [wipe the data folder](#start-completely-fresh-wipe-all-data) to re-initialize. ::: ## Change the PostgreSQL version Set the version in your `.env`: ```env POSTGRES_VERSION=16-alpine ``` Then apply the change: ```bash ./laradock rebuild postgres ``` ```bash docker compose build postgres ``` Changing the **major** version against an existing data folder can break startup (Postgres doesn't read another major version's data files). The safe way to move to a new major version without losing data: 1. **Back up first** (see [Backup and restore](#backup-and-restore) below): `./laradock exec -T postgres pg_dump -U default default > backup.sql` 2. Set the new `POSTGRES_VERSION` in `.env` and [start completely fresh](#start-completely-fresh-wipe-all-data), which wipes `DATA_PATH_HOST/postgres` and rebuilds on the new version. 3. Restore your backup into the fresh container: `./laradock exec -T postgres psql -U default -d default < backup.sql` ## Create multiple databases Copy `postgres/docker-entrypoint-initdb.d/createdb.sh.example` to `createdb.sh` in the same folder, then uncomment/set the database and user names you need: ```bash psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL CREATE USER db1 WITH PASSWORD 'db1'; CREATE DATABASE db1; GRANT ALL PRIVILEGES ON DATABASE db1 TO db1; EOSQL ``` This script only auto-runs the **first time** the container initializes its data folder (when `DATA_PATH_HOST/postgres` doesn't exist yet). If your data folder already exists, run the statements manually instead: ```bash ./laradock enter postgres psql -U default -d default ``` ```bash docker compose exec postgres bash psql -U default -d default ``` ## Backup and restore **Export (back up) a database** to a `.sql` file on your host: ```bash ./laradock exec -T postgres pg_dump -U default default > backup.sql ``` ```bash docker compose exec -T postgres pg_dump -U default default > backup.sql ``` Replace `default` with your database and user name (`POSTGRES_DB` / `POSTGRES_USER`). The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a database** from a `.sql` file: ```bash ./laradock exec -T postgres psql -U default -d default < backup.sql ``` ```bash docker compose exec -T postgres psql -U default -d default < backup.sql ``` Unlike the `createdb.sh` first-boot init script above, this works anytime, the target database (`default` here) just has to already exist. This is also how you bring in a dump from a client's production site or your previous local Postgres install. ## Start completely fresh (wipe all data) To throw away everything and start Postgres from a clean, empty state (this **permanently deletes** every database in this container, including any GitLab/Keycloak/SonarQube/Confluence databases seeded alongside it, back up first if you need anything): ```bash ./laradock stop postgres ./laradock remove postgres rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/postgres" ./laradock start postgres ``` ```bash docker compose stop postgres docker compose rm -sf postgres rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/postgres" docker compose up -d postgres ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where Postgres's data actually lives on your machine. Deleting it and starting again re-runs first-boot initialization: `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, and any `docker-entrypoint-initdb.d` scripts (including the `*_POSTGRES_INIT` seeding for GitLab/Keycloak/SonarQube/Confluence) all apply fresh, exactly like a brand-new install. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Postgres by container name out of the box. Easiest fix: publish the port (already done, `POSTGRES_PORT`) and have the other project connect to your **host machine's** address instead of `postgres`, for example `DB_HOST=host.docker.internal` (Docker Desktop) with `DB_PORT` set to this project's `POSTGRES_PORT`. Make sure the two projects use different `POSTGRES_PORT` values if they're both running at once. ## Connect from your host machine Inside Laradock, other containers reach Postgres by container name: `DB_HOST=postgres`. From your own machine (TablePlus, DBeaver, pgAdmin), connect to `localhost` on `POSTGRES_PORT` (`5432` by default) with the credentials above. ## Common issues - **"Access denied" / connection refused right after first boot.** The container needs a few seconds to initialize on a truly fresh `DATA_PATH_HOST`. Run `./laradock logs postgres` and wait for a "ready to accept connections" message before connecting. - **Credential/database changes don't take effect.** `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` are only applied when the data folder is created for the first time. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss, back up first) or create the new user/database manually after `./laradock enter postgres`. - **Two Laradock projects overwrite each other's data.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same Postgres data on disk. - **Port already in use on your host.** Another local Postgres (or another Laradock project) is already bound to `5432`. Change `POSTGRES_PORT` in `.env` and restart: `./laradock restart postgres`. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=postgres` (the container name), not `localhost` or `127.0.0.1`, those only work from your host machine, not from inside another container. - **Need PostGIS instead.** This plain `postgres` service has no geospatial extension; use **[postgres-postgis](https://laradock.io/docs/services/postgres-postgis)** if your app needs it. --- Need automated backups? See **[pgbackups](https://laradock.io/docs/services/pgbackups)**. Prefer a GUI? See pgAdmin in the **[Databases guide](https://laradock.io/docs/Intro#supported-services)**. ================================================================ # RethinkDB Source: https://laradock.io/docs/services/rethinkdb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is RethinkDB? [RethinkDB](https://rethinkdb.com/) is an open-source, document-oriented database built specifically for real-time apps: it can push live query results to clients as the underlying data changes. A community package, [Laravel RethinkDB](https://github.com/duxet/laravel-rethinkdb), provides Laravel integration. ## Start RethinkDB ```bash ./laradock start rethinkdb ``` ```bash docker compose up -d rethinkdb ``` Your data is created on first start and kept between restarts under `DATA_PATH_HOST/rethinkdb`. ## Stop RethinkDB Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop rethinkdb ``` ```bash docker compose stop rethinkdb ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/rethinkdb`): ```bash ./laradock remove rethinkdb ``` ```bash docker compose rm -sf rethinkdb ``` ## Configuration `rethinkdb/defaults.env` only exposes one setting, and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `RETHINKDB_PORT` | `8090` | Host-side port mapped to the container's admin console port (`8080` inside the container). | The RethinkDB client driver port (`28015` inside the container) is **not** published to your host, only reachable from other containers on Laradock's internal network via `rethinkdb:28015`. ## Open the admin console With the container running, open [http://localhost:8090/#tables](http://localhost:8090/#tables) (or your `RETHINKDB_PORT`) and create a database named `database` (or whatever you plan to reference from Laravel). ## Use RethinkDB from Laravel 1. Add a RethinkDB connection to `config/database.php`: ```php 'connections' => [ 'rethinkdb' => [ 'name' => 'rethinkdb', 'driver' => 'rethinkdb', 'host' => env('DB_HOST', 'rethinkdb'), 'port' => env('DB_PORT', 28015), 'database' => env('DB_DATABASE', 'test'), ] // ... ], ``` 2. In your Laravel `.env`, set `DB_CONNECTION=rethinkdb`, `DB_HOST=rethinkdb`, `DB_PORT=28015`, and `DB_DATABASE=database`. `DB_HOST=rethinkdb` and `DB_PORT=28015` only resolve from inside another Laradock container (like `workspace` or `php-fpm`); they aren't reachable from your host machine since that port isn't published. ## Backup and restore The `rethinkdb` image is built with RethinkDB's official Python driver, which bundles the `rethinkdb-dump` and `rethinkdb-restore` command-line tools. They only exist inside the RethinkDB container, so open a terminal there first, then dump straight into the mounted data folder so the archive lands on your host too: ```bash ./laradock enter rethinkdb rethinkdb-dump -f /data/rethinkdb_data/backup.tar.gz ``` ```bash docker compose exec rethinkdb bash rethinkdb-dump -f /data/rethinkdb_data/backup.tar.gz ``` With no `-e` flag, `rethinkdb-dump` exports every database on the server. The resulting archive is written to `DATA_PATH_HOST/rethinkdb/backup.tar.gz` on your host machine, since `/data/rethinkdb_data` is the volume mount. **Restore** the same archive later (into this container or a fresh one): ```bash ./laradock enter rethinkdb rethinkdb-restore /data/rethinkdb_data/backup.tar.gz ``` ```bash docker compose exec rethinkdb bash rethinkdb-restore /data/rethinkdb_data/backup.tar.gz ``` See RethinkDB's own docs on [backing up your data](https://www.rethinkdb.com/docs/backup/) for filtering to specific databases/tables with `-e`. ## Start completely fresh (wipe all data) To throw away everything and start RethinkDB from a clean, empty state (⚠️ this **permanently deletes** every database in this container, back up first if you need anything): ```bash ./laradock stop rethinkdb ./laradock remove rethinkdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/rethinkdb" ./laradock start rethinkdb ``` ```bash docker compose stop rethinkdb docker compose rm -sf rethinkdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/rethinkdb" docker compose up -d rethinkdb ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where RethinkDB's data actually lives on your machine. Unlike MySQL, RethinkDB doesn't auto-create any database on boot, you'll need to recreate it from the admin console or your backup afterward. ## Common issues - **Can't connect from a host GUI client.** The client-driver port (`28015`) isn't published to your host by `compose.yml`, only the admin console (`RETHINKDB_PORT` β†’ `8080`) is. Connect from inside a Laradock container instead, or add a port mapping yourself if you need host access. - **App can't connect but the container is running.** Confirm the app's `.env` uses `DB_HOST=rethinkdb` (the container name), not `localhost`. - **Admin console shows no tables.** You need to create the database/tables yourself the first time, RethinkDB doesn't auto-create anything on boot like MySQL's `MYSQL_DATABASE`. - **Port already in use on your host.** Change `RETHINKDB_PORT` in `.env` and restart with `./laradock restart rethinkdb`. --- Need a document database instead? See **[MongoDB](https://laradock.io/docs/services/mongo)**. For the full list of services, see **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Apache Solr Source: https://laradock.io/docs/services/solr ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Apache Solr? [Apache Solr](https://solr.apache.org) is a search platform built on Apache Lucene, offering full-text search, faceting, and indexing over HTTP. Laradock builds it from the official `solr` Docker image, with its admin UI and API on one port. ## Start Solr ```bash ./laradock start solr ``` ```bash docker compose up -d solr ``` Name any other services alongside it to start them together, for example `./laradock start solr mysql`. ## Stop Solr Stopping just pauses the container; **your cores are safe**, they live under `DATA_PATH_HOST/solr`: ```bash ./laradock stop solr ``` ```bash docker compose stop solr ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove solr ``` ```bash docker compose rm -sf solr ``` ## Configuration All settings live in `solr/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SOLR_VERSION` | `8.11` | Image tag from the [official Solr image](https://hub.docker.com/_/solr). | | `SOLR_PORT` | `8983` | Host-side port for both the admin UI and the API (container port `8983`). | | `SOLR_DATAIMPORTHANDLER_MYSQL` | `false` | When `true`, downloads the MySQL Connector/J JDBC driver at build time for the DataImportHandler. | | `SOLR_DATAIMPORTHANDLER_MSSQL` | `false` | When `true`, downloads the Microsoft JDBC driver at build time for the DataImportHandler. | ## Open the admin UI ``` http://localhost:8983/solr ``` ## Create a core ```bash ./laradock exec solr solr create_core -c mycore ``` ```bash docker compose exec solr solr create_core -c mycore ``` ## Check core status ```bash ./laradock exec solr solr status ``` ```bash docker compose exec solr solr status ``` You can also check a single core's health from the admin UI (**Core Admin** page) or by hitting `http://localhost:8983/solr/mycore/admin/ping`. ## Delete a core ```bash ./laradock exec solr solr delete -c mycore ``` ```bash docker compose exec solr solr delete -c mycore ``` ## Enable a JDBC data import connector 1. In `.env`, set `SOLR_DATAIMPORTHANDLER_MYSQL=true` (or `SOLR_DATAIMPORTHANDLER_MSSQL=true`). 2. Rebuild with a clean cache, since the connector is downloaded during the build: ```bash docker compose build --no-cache solr ``` ## Backup and restore a core Solr's replication handler can snapshot a core to disk and restore it later, no extra tooling needed. Both commands hit the core's own HTTP endpoint: **Back up** `mycore` (writes a `snapshot.` folder inside that core's data directory, under `DATA_PATH_HOST/solr/mycore/data`): ```bash curl "http://localhost:8983/solr/mycore/replication?command=backup" ``` Check `command=details` to confirm the backup finished before relying on it: ```bash curl "http://localhost:8983/solr/mycore/replication?command=details" ``` **Restore** the most recent snapshot back into `mycore`: ```bash curl "http://localhost:8983/solr/mycore/replication?command=restore" ``` Both commands run asynchronously; poll restore progress with `command=restorestatus`. Because the snapshot is written under `DATA_PATH_HOST/solr`, copying that folder off-host is also a valid manual backup. ## Start completely fresh (wipe all data) To throw away every core and start Solr from a clean, empty state (⚠️ this **permanently deletes** all cores and their indexed data, back up first if you need anything): ```bash ./laradock stop solr ./laradock remove solr rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/solr" ./laradock start solr ``` ```bash docker compose stop solr docker compose rm -sf solr rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/solr" docker compose up -d solr ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default). That folder is mounted straight to `/opt/solr/server/solr/mycores`, Solr's entire cores directory, so wiping it removes every core, not just their documents. After starting again you'll need to [create your cores](#create-a-core) from scratch. ## Tune the JVM heap size Solr's upstream image reads its JVM heap size from a `SOLR_HEAP` environment variable, but `solr/compose.yml` doesn't pass it through by default. Add it yourself under the `solr` service: ```yaml environment: - SOLR_HEAP=1g ``` Then apply the change: ```bash ./laradock restart solr ``` ```bash docker compose restart solr ``` Solr's default heap is fairly small (`512m`); indexing anything non-trivial usually calls for raising this. ## Talk to this Solr from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Solr by container name out of the box. Easiest fix: publish the port (already done, `SOLR_PORT`) and have the other project connect to your **host machine's** address instead of `solr`, for example `http://host.docker.internal:8983/solr` (Docker Desktop). Make sure the two projects use different `SOLR_PORT` values if they're both running at once. ## Common issues - **Changing `SOLR_VERSION` doesn't take effect.** It's a build argument, rebuild after changing it: `./laradock rebuild solr`. - **JDBC connectors missing.** They're only fetched when the matching flag was `true` at build time, flip the flag and rebuild with `docker compose build --no-cache solr`, a plain rebuild reuses the cached layer and skips the download. - **Cores don't persist across restarts.** They're written to `DATA_PATH_HOST/solr` (mounted to `/opt/solr/server/solr/mycores`), confirm `DATA_PATH_HOST` is set consistently between runs. - **Port already in use on your host.** Change `SOLR_PORT` in `.env` and restart: `./laradock restart solr`. - **Indexing is slow or Solr gets OOM-killed on large collections.** Raise the JVM heap, see [Tune the JVM heap size](#tune-the-jvm-heap-size) above. --- Need a lighter-weight search engine instead? See **[Manticore](https://laradock.io/docs/services/manticore)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # SSDB Source: https://laradock.io/docs/services/ssdb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is SSDB? [SSDB](https://github.com/ideawu/ssdb) is a high-performance NoSQL store built on LevelDB/RocksDB-style storage, supporting lists, hashes, sets, and z-sets like Redis. Unlike Redis, SSDB persists everything to disk rather than keeping the working set in memory, so it can hold datasets far larger than RAM while still speaking (a subset of) the Redis protocol. Laradock builds it from source on Alpine. ## Start SSDB ```bash ./laradock start ssdb ``` ```bash docker compose up -d ssdb ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start ssdb workspace`. ## Stop SSDB Stopping just pauses the container; **your data is safe**, it lives under `DATA_PATH_HOST/ssdb`: ```bash ./laradock stop ssdb ``` ```bash docker compose stop ssdb ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove ssdb ``` ```bash docker compose rm -sf ssdb ``` ## Configuration All settings live in `ssdb/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SSDB_PORT` | `16801` | Host-side port mapped to SSDB's internal port `8888`. | There's no version variable, `ssdb/Dockerfile` builds from the `master` branch of the [ideawu/ssdb](https://github.com/ideawu/ssdb) source and isn't pinned to a release tag. Server behavior itself (bind address, allowed IP ranges, replication, logging, storage engine tuning) is controlled by `ssdb/ssdb.conf`, which is baked into the image with `COPY` rather than mounted. Any edit to this file needs an image rebuild, not just a restart, to take effect: ```bash ./laradock rebuild ssdb ``` ```bash docker compose build ssdb ``` ## Connect with a client Because SSDB speaks the Redis protocol, `redis-cli` and most Redis clients work against it. From your host machine, connect to `localhost` on `SSDB_PORT` (`16801` by default): ```bash redis-cli -h 127.0.0.1 -p 16801 ``` From inside the container, `redis-cli` isn't installed, use SSDB's own `ssdb-cli` instead, which the build installs alongside `ssdb-server`: ```bash ./laradock enter ssdb ``` ```bash docker compose exec ssdb bash ``` ```bash /ssdb/ssdb-cli -p 8888 ``` ## Enable authentication By default SSDB has **no password**, anyone who can reach `SSDB_PORT` can read and write. `ssdb/ssdb.conf` has a commented-out `auth:` line under the `server:` block: ```conf server: #auth: very-strong-password ``` Uncomment it and set a password of **at least 32 characters**, then rebuild (it's a baked-in file, see [Configuration](#configuration) above) and restart: ```bash ./laradock rebuild ssdb ``` ```bash docker compose build ssdb ``` ```bash ./laradock restart ssdb ``` ```bash docker compose restart ssdb ``` Clients then need to run `AUTH your-password` (or pass `-a your-password` to `redis-cli`) before issuing other commands. ## Backup and restore SSDB has no built-in dump command in this build, but all of its data lives as plain files under `DATA_PATH_HOST/ssdb` (mounted to `/data` in the container), so a filesystem-level copy is a complete, reliable backup. Stop the container first so nothing is writing to the storage files mid-copy: ```bash ./laradock stop ssdb ``` ```bash docker compose stop ssdb ``` ```bash tar -czf ssdb-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/ssdb" . ``` Start it back up once the copy is done: ```bash ./laradock start ssdb ``` ```bash docker compose up -d ssdb ``` **Restore** by stopping SSDB, replacing the contents of that same data folder with your backup, then starting again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/ssdb"/* tar -xzf ssdb-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/ssdb" ``` ## Start completely fresh (wipe all data) To throw away everything and start SSDB from a clean, empty state (⚠️ this **permanently deletes** every key in this container, back up first if you need anything): ```bash ./laradock stop ssdb ./laradock remove ssdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/ssdb" ./laradock start ssdb ``` ```bash docker compose stop ssdb docker compose rm -sf ssdb rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/ssdb" docker compose up -d ssdb ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where SSDB's data actually lives on your machine. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this SSDB by container name out of the box. Easiest fix: the port is already published (`SSDB_PORT`), have the other project connect to your **host machine's** address instead of `ssdb`, for example `host.docker.internal` (Docker Desktop) on this project's `SSDB_PORT`. Make sure the two projects use different `SSDB_PORT` values if they're both running at once. ## Common issues - **Connections refused from other hosts.** `ssdb/ssdb.conf` only allows `127.0.0.1`, `192.*`, and `172.*` by default (`allow:` lines under `server:`), edit that file and rebuild (`./laradock rebuild ssdb`) if you need to allow a different range. - **Image drifts over time.** Since the build isn't pinned to a release tag, rebuilding without cache can pull in newer upstream commits than you tested against. - **Data not persisting.** Confirm `DATA_PATH_HOST` is set consistently, SSDB's data is written to `DATA_PATH_HOST/ssdb` on the host. - **Port already in use on your host.** Change `SSDB_PORT` in `.env` and restart: `./laradock restart ssdb`. - **Config edits not taking effect.** `ssdb.conf` is copied into the image at build time, not mounted, so any change needs `./laradock rebuild ssdb` followed by `./laradock restart ssdb`. --- Need an in-memory store instead? See the **[Databases guide](https://laradock.io/docs/Intro#supported-services)** for Redis and friends. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # SurrealDB Source: https://laradock.io/docs/services/surrealdb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is SurrealDB? [SurrealDB](https://surrealdb.com) is a multi-model database combining document, graph, and relational data behind a single SQL-like query language (SurrealQL), reachable over both REST and WebSocket. Laradock runs it from the official `surrealdb/surrealdb` image with a RocksDB storage backend. ## Start SurrealDB ```bash ./laradock start surrealdb ``` ```bash docker compose up -d surrealdb ``` Data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start surrealdb redis`. ## Stop SurrealDB Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop surrealdb ``` ```bash docker compose stop surrealdb ``` To delete the container entirely (the data is still safe, it lives in the named `surrealdb` Docker volume, not in the container): ```bash ./laradock remove surrealdb ``` ```bash docker compose rm -sf surrealdb ``` ## Configuration All settings live in `surrealdb/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SURREALDB_VERSION` | `v2.6.5` | Image tag from [SurrealDB's Docker Hub image](https://hub.docker.com/r/surrealdb/surrealdb). | | `SURREALDB_PORT` | `8010` | Host-side port for the REST/WebSocket API (container port `8000`). | | `SURREALDB_USER` | `root` | Root user, passed to `surreal start --user`. | | `SURREALDB_PASSWORD` | `secret` | Root password, passed to `surreal start --pass`. | The container runs as `root` (set in `surrealdb/compose.yml`) so the server can create its RocksDB store inside the named volume, and starts with: ``` start --user ${SURREALDB_USER} --pass ${SURREALDB_PASSWORD} --bind 0.0.0.0:8000 rocksdb:/data/database.db ``` There's no `SURREALDB_NAMESPACE`/`SURREALDB_DATABASE` variable: unlike MySQL's `MYSQL_DATABASE`, SurrealDB doesn't pre-create a namespace or database for you. You choose both yourself, either with `USE NS your_ns DB your_db;` in a query session, or with `--ns`/`--db` flags on the CLI, they're created automatically the first time you use them. ## Change the SurrealDB version Set the version in your `.env`: ```env SURREALDB_VERSION=v2.7.0 ``` Then apply the change (the image is pulled by tag, not built locally, so starting again is enough to pull and switch to it): ```bash ./laradock start surrealdb ``` ```bash docker compose up -d surrealdb ``` Moving to a new major version against an existing RocksDB store on disk isn't guaranteed safe. Back up first (see [Backup and restore](#backup-and-restore) below), and if startup fails after the version bump, [start completely fresh](#start-completely-fresh-wipe-all-data) and restore your export into the new version. ## Check it's up ```bash curl http://localhost:8010/health ``` ## Connect Use the [SurrealDB CLI](https://surrealdb.com/docs/surrealdb/cli) or any SurrealDB client library against `http://localhost:8010` (from your host) or `http://surrealdb:8000` (from another container), authenticating with `SURREALDB_USER` / `SURREALDB_PASSWORD`. ## Run SurrealQL queries Open a terminal inside the SurrealDB container, then start the SurrealQL shell against your own namespace/database (replace `test`/`test` with your own): ```bash ./laradock enter surrealdb surreal sql --conn http://localhost:8000 --user root --pass secret --ns test --db test ``` ```bash docker compose exec surrealdb bash surreal sql --conn http://localhost:8000 --user root --pass secret --ns test --db test ``` ```sql DEFINE TABLE person SCHEMALESS; CREATE person SET name = "Laradock"; SELECT * FROM person; ``` ## Backup and restore **Export a namespace/database** to a `.surql` file on your host (replace `test`/`test` with your own namespace/database): ```bash ./laradock exec -T surrealdb surreal export --conn http://localhost:8000 --user root --pass secret --ns test --db test - > backup.surql ``` ```bash docker compose exec -T surrealdb surreal export --conn http://localhost:8000 --user root --pass secret --ns test --db test - > backup.surql ``` The `-T` disables the container's pseudo-terminal so the export isn't corrupted when redirected to a file, always include it when piping output to or from a file. **Restore (import) a namespace/database** from a `.surql` file: ```bash ./laradock exec -T surrealdb surreal import --conn http://localhost:8000 --user root --pass secret --ns test --db test - < backup.surql ``` ```bash docker compose exec -T surrealdb surreal import --conn http://localhost:8000 --user root --pass secret --ns test --db test - < backup.surql ``` This works anytime, the target namespace/database doesn't need to exist first, `surreal import` creates it. This is also how you bring in a `.surql` export from another environment. ## Start completely fresh (wipe all data) To throw away everything and start SurrealDB from a clean, empty state (⚠️ this **permanently deletes** every namespace/database in this container, back up first if you need anything): ```bash ./laradock stop surrealdb ./laradock remove surrealdb docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_surrealdb ./laradock start surrealdb ``` ```bash docker compose stop surrealdb docker compose rm -sf surrealdb docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_surrealdb docker compose up -d surrealdb ``` Unlike MySQL and other services that store data under `DATA_PATH_HOST`, SurrealDB's RocksDB store lives in a named Docker volume, not a host folder. Confirm the exact volume name first with `docker volume ls | grep surrealdb` if you're unsure what `COMPOSE_PROJECT_NAME` resolves to (it's set in your `.env`). ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this SurrealDB by container name out of the box. Easiest fix: publish the port (already done, `SURREALDB_PORT`) and have the other project connect to your **host machine's** address instead of `surrealdb`, for example `http://host.docker.internal:8010` (Docker Desktop). Make sure the two projects use different `SURREALDB_PORT` values if they're both running at once. ## Common issues - **Changing `SURREALDB_VERSION` doesn't take effect.** SurrealDB is pulled by image tag, not built locally, apply it with `./laradock start surrealdb`. - **Credential changes don't take effect.** `SURREALDB_USER`/`SURREALDB_PASSWORD` are only meaningful the first time the RocksDB store is created inside the volume. If you change them afterward, either [start completely fresh](#start-completely-fresh-wipe-all-data) (data loss) or manage users through SurrealQL instead. - **Data isn't where you expect.** Persists to a named Docker volume (`surrealdb`), not `DATA_PATH_HOST`. Use `docker volume inspect _surrealdb` to find it. - **"There was a problem with the database" / queries fail with no namespace/database selected.** SurrealDB doesn't pre-create a namespace or database like `MYSQL_DATABASE` does. Add `--ns`/`--db` flags to the CLI, or run `USE NS your_ns DB your_db;` first, in every session. - **Port already in use on your host.** Another local SurrealDB (or another Laradock project) is already bound to `8010`. Change `SURREALDB_PORT` in `.env` and restart: `./laradock restart surrealdb`. --- Need a different multi-model option? See **[ArangoDB](https://laradock.io/docs/services/arangodb)**. Back to the **[Getting Started guide](https://laradock.io/docs/getting-started)**. ================================================================ # Certbot Source: https://laradock.io/docs/services/certbot ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Certbot? [Certbot](https://certbot.eff.org) is the standard client for [Let's Encrypt](https://letsencrypt.org), issuing free, automated TLS/SSL certificates. Laradock runs it as a one-shot container that requests a certificate via the HTTP-01 "webroot" challenge, it doesn't serve traffic itself, it just proves domain ownership through your existing web server and writes out the certificate files. ## Start Certbot ```bash ./laradock start certbot ``` ```bash docker compose up -d certbot ``` Certbot needs a domain that already resolves to your server and a web server (`nginx`, `apache2`, or `caddy`) listening on port 80 to serve the challenge, since the webroot method requires Let's Encrypt to fetch a file over plain HTTP before it will issue a certificate. ## Stop Certbot ```bash ./laradock stop certbot ``` ```bash docker compose stop certbot ``` Certbot's `run-certbot.sh` runs once at container start and then the container just sleeps, so stopping it is safe at any time and doesn't affect certificates already issued. ## Configuration `certbot/defaults.env` is empty. The two values Certbot needs, domain and email, are hardcoded directly in `certbot/compose.yml`: ```yaml environment: - CN="fake.domain.com" - EMAIL="fake.email@gmail.com" ``` Edit `certbot/compose.yml` and replace `CN` with your real domain and `EMAIL` with your real address, then rebuild: ```bash ./laradock rebuild certbot ``` ```bash docker compose build certbot ``` ## How the certificate is issued `certbot/Dockerfile` builds on `phusion/baseimage:bionic-1.0.0`, installs the `letsencrypt` apt package, and runs `certbot/run-certbot.sh` as its entrypoint: ```bash letsencrypt certonly --webroot -w /var/www/letsencrypt -d "$CN" --agree-tos --email "$EMAIL" --non-interactive --text ``` `/var/www/letsencrypt` inside the container is bind-mounted from `./certbot/letsencrypt/` on your host. For the challenge to succeed, your web server must serve that same folder at `http://your-domain/.well-known/acme-challenge/`. Laradock's shipped `nginx/sites/*.conf` files already include that `location` block pointing at `/var/www/letsencrypt/`, but as of this writing `nginx/compose.yml` does not itself mount `./certbot/letsencrypt/` into the nginx container, so you need to add that volume mapping to `nginx/compose.yml` (or your `apache2`/`caddy` equivalent) yourself before Certbot's challenge can be reached. On success, `run-certbot.sh` copies the issued files into `./data/certbot/certs/` on your host: - `-cert1.pem` - `chain1.pem` - `fullchain1.pem` - `-privkey1.pem` Point your web server's SSL config at those files. ## Check whether it succeeded Certbot's entrypoint runs `run-certbot.sh` once, then sleeps, it doesn't stay attached to your terminal, so check the container's logs to see whether the challenge actually succeeded or Let's Encrypt rejected it: ```bash ./laradock logs certbot ``` ```bash docker compose logs --tail=100 certbot ``` Success shows `Congratulations!` from `letsencrypt` and the four `.pem` files listed above under `./data/certbot/certs/`. Any other outcome means the challenge failed, see [Common issues](#common-issues). ## Test with the staging environment first Every real request against Let's Encrypt's production endpoint counts against its per-domain rate limits, so if you're still iterating on your domain/DNS/web-server setup, point Certbot at Let's Encrypt's staging endpoint instead, it issues certificates your browser won't trust, but doesn't count against production rate limits. Add `--staging` to the `letsencrypt certonly` line in `certbot/run-certbot.sh`: ```bash letsencrypt certonly --webroot -w /var/www/letsencrypt -d "$CN" --agree-tos --email "$EMAIL" --non-interactive --text --staging ``` Rebuild and start Certbot as above. Once the staging run succeeds, remove the `--staging` flag and rebuild again to get the real, browser-trusted certificate. ## Renew the certificate Let's Encrypt certificates expire after 90 days, and this container doesn't set up any renewal cron, `run-certbot.sh` only ever runs once, at container start. To renew, just start it again the same way you did the first time: ```bash ./laradock restart certbot ``` ```bash docker compose restart certbot ``` For unattended renewal, schedule that same command on your host (e.g. a monthly host `cron` entry) well before the 90-day expiry, and confirm success afterward with [Check whether it succeeded](#check-whether-it-succeeded) above. ## Common issues - **Challenge fails / "Invalid response" from Let's Encrypt.** Almost always means the web server isn't serving `./certbot/letsencrypt/` at `/.well-known/acme-challenge/` on port 80, or the domain doesn't resolve to this server yet. Confirm the volume mapping and DNS before retrying. - **Still using `fake.domain.com` / `fake.email@gmail.com`.** These are placeholders in `certbot/compose.yml`. Certbot will fail (or issue a cert nobody can use) until you set them to real values and rebuild. - **Rate limited by Let's Encrypt.** Let's Encrypt caps retries per domain per week. [Test with their staging environment first](#test-with-the-staging-environment-first) if you're iterating on config. - **Certificate doesn't renew automatically.** See [Renew the certificate](#renew-the-certificate), `./laradock restart certbot` (or your own cron) is required, there's nothing automatic here. --- Pair this with **[nginx](https://laradock.io/docs/services/nginx)** or **[Apache2](https://laradock.io/docs/services/apache2)** to actually serve HTTPS traffic. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Docker in Docker Source: https://laradock.io/docs/services/docker-in-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Docker in Docker? Docker in Docker (dind) runs a full Docker daemon *inside* a container, so that container (or others pointed at it) can build images and run containers of their own. It's the standard way to give a CI runner (Jenkins, GitLab Runner, a custom pipeline) the ability to `docker build`/`docker run` without mounting the host's Docker socket. Laradock runs the official `docker:29-dind` image, unmodified. ## Start Docker in Docker ```bash ./laradock start docker-in-docker ``` ```bash docker compose up -d docker-in-docker ``` The container runs `privileged: true` (required for dind to manage its own cgroups and networking) and stays up via `restart: always`. ## Stop Docker in Docker ```bash ./laradock stop docker-in-docker ``` ```bash docker compose stop docker-in-docker ``` This stops the daemon container. Any images or containers built inside it are stored in the named `docker-in-docker` volume (mounted at `/certs/client`) and Docker's internal storage, both of which persist until the volume is removed. To delete the container entirely (the named volume, and everything dind stored inside it, is still untouched): ```bash ./laradock remove docker-in-docker ``` ```bash docker compose rm -sf docker-in-docker ``` ## Configuration There is no `docker-in-docker/defaults.env` file, this service has no Laradock-specific environment variables. What is configured, directly in `docker-in-docker/compose.yml`: | Setting | Value | What it does | |---|---|---| | `image` | `docker:29-dind` | The Docker-in-Docker image and version. | | `DOCKER_TLS_SAN` | `DNS:docker-in-docker` | Adds the container name to the daemon's TLS certificate so clients can connect to it as `docker-in-docker` over TLS. | | `privileged` | `true` | Required for the inner daemon to operate. | | `expose` | `2375` | The Docker daemon port is exposed to other containers on the `backend` network only, it is not published to your host. | To change the image tag (for example to pin a different Docker version), edit the `image:` line in `docker-in-docker/compose.yml` directly, then re-run the start command above, it will pull the new tag and recreate the container. ## Run Docker commands directly inside it Useful for checking the daemon is healthy, or for testing a build manually before wiring up a CI runner: ```bash ./laradock enter docker-in-docker ``` ```bash docker compose exec docker-in-docker sh ``` Then, inside the container, use the `docker` client that ships with the image against its own local daemon: ```sh docker version docker ps ``` ## Connect to it from another container Other containers on the `backend` network can point their Docker client at this daemon by setting `DOCKER_HOST=tcp://docker-in-docker:2375` (matching the exposed port). The `${APP_CODE_PATH_HOST}` folder is mounted into the container at `${APP_CODE_PATH_CONTAINER}`, so your project code is available if a build needs it, and TLS client certs are shared via the `docker-in-docker` named volume at `/certs/client`. There is no host port mapping, so you cannot reach this daemon directly from your host machine, only from containers on the same Laradock network. ## Reset it (wipe everything dind has built or pulled) To reclaim disk space or start the inner daemon from a completely clean state, remove the container and its named volume, then start again: ```bash ./laradock stop docker-in-docker ./laradock remove docker-in-docker docker volume rm $(docker volume ls -q --filter name=docker-in-docker) ./laradock start docker-in-docker ``` ```bash docker compose stop docker-in-docker docker compose rm -sf docker-in-docker docker volume rm $(docker volume ls -q --filter name=docker-in-docker) docker compose up -d docker-in-docker ``` This deletes every image, container, and layer the inner daemon has ever built or pulled, along with its TLS client certs. There is nothing else to back up first, unlike a database this container holds no data your app depends on directly. ## Common issues - **Can't connect from a CI runner container.** Make sure the runner container is on the same `backend` network and points `DOCKER_HOST` at `tcp://docker-in-docker:2375`, not `localhost`. - **`Cannot connect to the Docker daemon`.** Give the dind container a few seconds to initialize after starting it; check `./laradock logs docker-in-docker` for the daemon's "API listen on" line. - **Builds fail with permission or cgroup errors.** dind requires `privileged: true`, which is already set in `docker-in-docker/compose.yml`. If you've customized the compose file and removed it, the daemon won't start correctly. - **Nested images vanish after `docker compose down -v`.** The `-v` flag removes named volumes, including the `docker-in-docker` volume backing this container's certs and layers. Use `./laradock stop docker-in-docker` (or plain `docker compose down` without `-v`) if you want to keep them. --- Want your own place to push the images this builds? See **[Docker Registry](https://laradock.io/docs/services/docker-registry)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Docker Registry Source: https://laradock.io/docs/services/docker-registry ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Docker Registry? [Docker Registry](https://hub.docker.com/_/registry) (also called Distribution) is the official open-source server for storing and distributing Docker images. Running your own instance lets you push and pull images without relying on Docker Hub or a paid registry service, useful for private images, air-gapped environments, or CI pipelines that need a local cache. Laradock builds it from the official `registry:2` image. ## Start Docker Registry ```bash ./laradock start docker-registry ``` ```bash docker compose up -d docker-registry ``` ## Stop Docker Registry Stopping just pauses the container; your images on disk are safe: ```bash ./laradock stop docker-registry ``` ```bash docker compose stop docker-registry ``` To delete the container entirely (the data on disk is untouched, it lives under `DATA_PATH_HOST/docker-registry`): ```bash ./laradock remove docker-registry ``` ```bash docker compose rm -sf docker-registry ``` ## Configuration All settings live in `docker-registry/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `DOCKER_REGISTRY_PORT` | `5000` | Host-side port the registry's HTTP API is published on (`host:5000`). | That's the only variable Laradock exposes; everything else is the stock `registry:2` image behavior, tunable by adding an `environment:` block to `docker-registry/compose.yml` (see [Secure the registry with authentication](#secure-the-registry-with-authentication) and [Enable image deletion and garbage collection](#enable-image-deletion-and-garbage-collection) below). ## Push and pull images The registry stores image data under `DATA_PATH_HOST/docker-registry` on your host (mounted to `/var/lib/registry` in the container), so images survive container restarts and rebuilds. From your host machine (registry reachable on `localhost:5000` by default): ```bash docker tag your-image:latest localhost:5000/your-image:latest docker push localhost:5000/your-image:latest docker pull localhost:5000/your-image:latest ``` From another container on Laradock's `backend` network, use the container name instead of `localhost`: `docker-registry:5000`. ## Browse what's stored (the catalog API) The registry has no built-in web UI, but it exposes its contents over its own HTTP API. List every repository: ```bash curl http://localhost:5000/v2/_catalog ``` List the tags pushed for one repository: ```bash curl http://localhost:5000/v2/your-image/tags/list ``` ## Backup and restore **Back up** every image by archiving the data folder on your host (stop the container first so nothing is mid-write): ```bash ./laradock stop docker-registry ``` ```bash docker compose stop docker-registry ``` ```bash tar -czf docker-registry-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" . ``` **Restore** by extracting that archive back into the data folder before starting the container again: ```bash mkdir -p "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" tar -xzf docker-registry-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" ``` This is a plain filesystem copy, no special export/import tool is needed since the registry's storage driver is just files on disk. ## Start completely fresh (wipe all data) To throw away every pushed image and start from a clean, empty registry (this **permanently deletes** everything in it, back up first if you need anything): ```bash ./laradock stop docker-registry ./laradock remove docker-registry rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" ./laradock start docker-registry ``` ```bash docker compose stop docker-registry docker compose rm -sf docker-registry rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/docker-registry" docker compose up -d docker-registry ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where every pushed image actually lives on your machine. ## Enable image deletion and garbage collection By default the registry accepts pushes but refuses `DELETE` requests, so old tags pile up forever. To allow deleting image manifests, add an `environment:` block to the `docker-registry` service in `docker-registry/compose.yml`: ```yaml environment: - REGISTRY_STORAGE_DELETE_ENABLED=true ``` Then rebuild: ```bash ./laradock restart docker-registry ``` ```bash docker compose up -d docker-registry ``` Deleting a manifest only unlinks it, it doesn't reclaim disk space right away. Run the registry's own garbage collector afterward to actually free it up: ```bash ./laradock enter docker-registry ``` ```bash docker compose exec docker-registry bash ``` ```bash registry garbage-collect /etc/docker/registry/config.yml ``` ## Secure the registry with authentication Out of the box the registry has **no authentication**, anyone who can reach `DOCKER_REGISTRY_PORT` can push and pull. That's fine on a machine only you can reach, but worth locking down if the port is ever exposed beyond your own host. The stock `registry:2` image supports HTTP Basic auth via an htpasswd file: generate one, mount it, and point the registry at it with an `environment:`/`volumes:` block in `docker-registry/compose.yml`: ```yaml environment: - REGISTRY_AUTH=htpasswd - REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm - REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd volumes: - ./docker-registry/auth:/auth ``` Generate the htpasswd file with `htpasswd` (from the `apache2-utils`/`httpd-tools` package) before starting: ```bash htpasswd -Bc docker-registry/auth/htpasswd your-username ``` After that, `docker login localhost:5000` is required before any push/pull against this registry. ## Common issues - **`http: server gave HTTP response to HTTPS client`.** The stock registry image serves plain HTTP, not HTTPS. Docker's client refuses to push/pull over HTTP to a registry it doesn't consider `localhost` by default. If you're hitting it from another machine or a non-`localhost` hostname, add it to your Docker daemon's `insecure-registries` list. - **Port already in use on your host.** Another local registry (or another Laradock project) is already bound to `5000`. Change `DOCKER_REGISTRY_PORT` in `.env` and restart: `./laradock restart docker-registry`. - **Pushed images disappear after a rebuild.** Confirm `DATA_PATH_HOST` didn't change between runs. The registry's storage is bind-mounted from your host, so a different `DATA_PATH_HOST` means a different (empty) image store. - **Two Laradock projects overwrite each other's images.** Running more than one Laradock on the same machine? Set both `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` to unique values per project, otherwise they share the same registry data on disk. - **`DELETE` requests return 405 Method Not Allowed.** Image deletion is off by default, see [Enable image deletion and garbage collection](#enable-image-deletion-and-garbage-collection) above. --- Need to build and run Docker-in-Docker for CI-style workflows? See **[Docker in Docker](https://laradock.io/docs/services/docker-in-docker)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # GitLab Runner Source: https://laradock.io/docs/services/gitlab-runner ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is GitLab Runner? [GitLab Runner](https://docs.gitlab.com/runner/) is the agent that picks up and executes jobs defined in a project's `.gitlab-ci.yml`. It pairs with the **[GitLab](https://laradock.io/docs/services/gitlab)** service: GitLab schedules pipelines, the runner actually executes them. ## Start GitLab Runner ```bash ./laradock start gitlab-runner ``` ```bash docker compose up -d gitlab-runner ``` ## Stop GitLab Runner ```bash ./laradock stop gitlab-runner ``` ```bash docker compose stop gitlab-runner ``` ## Configuration All settings live in `gitlab-runner/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `GITLAB_CI_SERVER_URL` | `http://localhost:8989` | URL of the GitLab instance the runner registers against. | | `GITLAB_RUNNER_REGISTRATION_TOKEN` | `` | Token from your GitLab project used to register the runner. | | `GITLAB_REGISTER_NON_INTERACTIVE` | `true` | Runs `gitlab-runner register` without prompting when set. | By default `gitlab-runner/compose.yml` runs the runner with `RUNNER_EXECUTOR=shell` and mounts `/var/run/docker.sock`, so you can switch to a Docker executor instead (see below). Its config and registration state persist under `DATA_PATH_HOST/gitlab/runner` (mounted to `/etc/gitlab-runner` in the container). ## Register the runner against GitLab 1. In your GitLab project, go to **Settings β†’ CI/CD β†’ Runners** and copy the registration token. 2. Set these in `.env` (use the container name, not `localhost`, since the runner talks to GitLab over the Docker network): ```env GITLAB_CI_SERVER_URL=http://gitlab GITLAB_RUNNER_REGISTRATION_TOKEN= ``` 3. To use the Docker executor instead of the default shell executor, add this to `gitlab-runner/compose.yml`: ```yml gitlab-runner: environment: # used during `gitlab-runner register` - RUNNER_EXECUTOR=docker # change from shell (default) - DOCKER_IMAGE=alpine - DOCKER_NETWORK_MODE=laradock_backend networks: - backend # connect to the network where gitlab runs ``` 4. Start the runner: ```bash ./laradock start gitlab-runner ``` ```bash docker compose up -d gitlab-runner ``` 5. Register it: ```bash ./laradock enter gitlab-runner gitlab-runner register ``` ```bash docker compose exec gitlab-runner bash gitlab-runner register ``` With `GITLAB_REGISTER_NON_INTERACTIVE=true` (the default), `register` picks up `CI_SERVER_URL` and `REGISTRATION_TOKEN` from the environment automatically and doesn't prompt you for them. 6. Add a `.gitlab-ci.yml` to your project, push, and confirm the pipeline runs: ```yml before_script: - echo Hello! job1: scripts: - echo job1 ``` ## Check runner status and logs ```bash ./laradock logs gitlab-runner ``` ```bash docker compose logs --tail=100 gitlab-runner ``` To list every runner currently registered against this container (useful after re-registering or when you're not sure whether registration actually took): ```bash ./laradock enter gitlab-runner gitlab-runner list ``` ```bash docker compose exec gitlab-runner bash gitlab-runner list ``` ## Unregister a runner Do this before re-registering with different settings (a new executor, a different GitLab instance), stale registrations otherwise pile up in `config.toml`: ```bash ./laradock enter gitlab-runner gitlab-runner unregister --all-runners ``` ```bash docker compose exec gitlab-runner bash gitlab-runner unregister --all-runners ``` ## Start completely fresh (wipe registration) Registration state and `config.toml` live under `DATA_PATH_HOST/gitlab/runner` on your host. To throw it away and register from a clean state: ```bash ./laradock stop gitlab-runner ./laradock remove gitlab-runner rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/gitlab/runner" ./laradock start gitlab-runner ``` ```bash docker compose stop gitlab-runner docker compose rm -sf gitlab-runner rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/gitlab/runner" docker compose up -d gitlab-runner ``` You'll need to run [Register the runner against GitLab](#register-the-runner-against-gitlab) again afterward, the registration token from GitLab is still valid, only this container's local state was wiped. ## Common issues - **Runner registers but jobs never pick up.** Confirm `GITLAB_CI_SERVER_URL` points to a URL the runner container can actually reach, `http://gitlab` (container name), not `http://localhost`. - **`REGISTRATION_TOKEN` rejected.** Tokens are per-project (or per-group/instance depending on your GitLab setup) and can be regenerated in GitLab's **Settings β†’ CI/CD β†’ Runners**, grab a fresh one if registration fails. - **Docker-executor jobs can't reach other Laradock services.** Make sure `DOCKER_NETWORK_MODE` matches your actual Compose project's network name (`laradock_backend` by default, but it's prefixed by `COMPOSE_PROJECT_NAME`). - **Re-registering after changing executors.** Changing `RUNNER_EXECUTOR` after the runner is already registered doesn't retroactively apply, [unregister](#unregister-a-runner) and register again, or [start completely fresh](#start-completely-fresh-wipe-registration). --- Need the GitLab server this runner connects to? See **[GitLab](https://laradock.io/docs/services/gitlab)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # GitLab Source: https://laradock.io/docs/services/gitlab ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is GitLab? [GitLab](https://about.gitlab.com) is a self-hosted Git server with built-in issue tracking, code review, and CI/CD pipelines. Laradock runs the Omnibus image as its own container, wired to the `postgres` and `redis` services that are already part of the stack. ## Start GitLab ```bash ./laradock start gitlab ``` ```bash docker compose up -d gitlab ``` GitLab depends on `redis` and `postgres` (declared in `gitlab/compose.yml`), so starting it starts both automatically. First boot takes a while, GitLab is a large application; watch progress with: ```bash ./laradock logs gitlab ``` ```bash docker compose logs -f gitlab ``` ## Stop GitLab Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop gitlab ``` ```bash docker compose stop gitlab ``` GitLab's config, repositories, and logs live under `DATA_PATH_HOST` and `GITLAB_HOST_LOG_PATH` on your host, stopping (or even deleting) the container never touches them. To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove gitlab ``` ```bash docker compose rm -sf gitlab ``` ## Configuration All settings live in `gitlab/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `GITLAB_HOST_HTTP_PORT` | `8989` | Host-side port for the GitLab web UI (HTTP). | | `GITLAB_HOST_HTTPS_PORT` | `9898` | Host-side port for the GitLab web UI (HTTPS). | | `GITLAB_HOST_SSH_PORT` | `2289` | Host-side port for Git-over-SSH. | | `GITLAB_DOMAIN_NAME` | `http://localhost` | External URL GitLab advertises itself as; set this to your real domain in production. | | `GITLAB_ROOT_PASSWORD` | `laradock` | Initial password for the `root` user. | | `GITLAB_HOST_LOG_PATH` | `./logs/gitlab` | Host folder mounted to `/var/log/gitlab`. | | `GITLAB_POSTGRES_HOST` | `postgres` | Hostname of the Postgres container GitLab connects to. | GitLab also needs `GITLAB_POSTGRES_USER`, `GITLAB_POSTGRES_PASSWORD`, and `GITLAB_POSTGRES_DB` to create its database in Postgres. These aren't in `gitlab/defaults.env`, they ship as top-level defaults in `.env.example` (`laradock_gitlab` for all three). The `postgres` service also needs `GITLAB_POSTGRES_INIT=true` (set by default in `postgres/defaults.env`) to auto-create that database and user on its first boot. ## Set your domain ```env GITLAB_DOMAIN_NAME=http://localhost ``` Change this to your real domain (or `https://` URL) before exposing GitLab beyond local dev, GitLab uses it to generate links, clone URLs, and webhooks. `GITLAB_DOMAIN_NAME` feeds straight into the Omnibus `external_url` setting (see `gitlab/compose.yml`), so a container restart is enough to pick it up, no rebuild needed: ```bash ./laradock restart gitlab ``` ```bash docker compose restart gitlab ``` ## Reset the root password If you changed `GITLAB_ROOT_PASSWORD` after the data volume already existed, GitLab won't pick it up (it's only applied on first boot, just like the database credentials above). Reset it from inside the container instead. Open a terminal and start GitLab's Rails console: ```bash ./laradock enter gitlab gitlab-rails console ``` ```bash docker compose exec gitlab bash gitlab-rails console ``` Then, inside the Rails console: ```ruby user = User.find_by(username: 'root') user.password = 'your_new_password' user.password_confirmation = 'your_new_password' user.save! ``` ## Backup and restore **Create a backup** (repositories, uploads, and the Postgres database, written to `/var/opt/gitlab/backups` inside the container, which lives under `DATA_PATH_HOST/gitlab/data/backups` on your host): ```bash ./laradock enter gitlab gitlab-backup create ``` ```bash docker compose exec gitlab bash gitlab-backup create ``` A backup archive alone isn't enough to restore GitLab on a different machine or after a full reset, GitLab also needs its secrets file to decrypt CI/CD variables and two-factor secrets. Copy that out separately, straight from the host (it's bind-mounted, no container access needed): ```bash cp "${DATA_PATH_HOST:-~/.laradock/data}/gitlab/config/gitlab-secrets.json" ./gitlab-secrets.json.bak ``` **Restore a backup.** Put the backup `.tar` file into `DATA_PATH_HOST/gitlab/data/backups` (and `gitlab-secrets.json` back into `DATA_PATH_HOST/gitlab/config` if you're restoring onto a fresh instance), then run: ```bash ./laradock enter gitlab gitlab-backup restore BACKUP= ``` ```bash docker compose exec gitlab bash gitlab-backup restore BACKUP= ``` `` is the numeric prefix of the `.tar` file in the backups folder (GitLab prints it after `gitlab-backup create` too). Restoring stops and restarts GitLab's internal services and prompts for confirmation before overwriting existing data. ## Start completely fresh (wipe all data) To throw away everything, every user, repository, and setting, and start GitLab from a clean, empty state (⚠️ this **permanently deletes** all of it, back up first if you need anything): ```bash ./laradock stop gitlab ./laradock remove gitlab rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/gitlab" rm -rf "${GITLAB_HOST_LOG_PATH:-./logs/gitlab}" ./laradock start gitlab ``` ```bash docker compose stop gitlab docker compose rm -sf gitlab rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/gitlab" rm -rf "${GITLAB_HOST_LOG_PATH:-./logs/gitlab}" docker compose up -d gitlab ``` `DATA_PATH_HOST/gitlab` holds both `config` (`/etc/gitlab`, including `gitlab-secrets.json`) and `data` (`/var/opt/gitlab`, repos and the Rails app data); `GITLAB_HOST_LOG_PATH` is a separate, relative-by-default path (`./logs/gitlab`). Deleting both and starting again re-runs GitLab's own first-boot setup: `GITLAB_ROOT_PASSWORD`, `GITLAB_DOMAIN_NAME`, and the Postgres database from `GITLAB_POSTGRES_*` all apply fresh, exactly like a brand-new install. ## Edit `gitlab.rb` directly For Omnibus settings that don't have a `.env` variable in Laradock yet, edit the config file GitLab itself uses. It's bind-mounted to your host at `DATA_PATH_HOST/gitlab/config/gitlab.rb`, so you can edit it from either side. Unlike the `.env` variables above (which regenerate this file on every container start), manual edits need an explicit reconfigure to take effect: ```bash ./laradock enter gitlab gitlab-ctl reconfigure ``` ```bash docker compose exec gitlab bash gitlab-ctl reconfigure ``` Note that `GITLAB_OMNIBUS_CONFIG` (built from the `.env` variables in the [Configuration](#configuration) table above) is reapplied on every container restart, so a manual `gitlab-rb` edit can be overwritten by it on the next restart unless you also add the same setting to `gitlab/compose.yml`. ## Check what's running inside the container GitLab's Omnibus image bundles many internal services (Puma, Sidekiq, Gitaly, Postgres connection pooling, etc.), all supervised by `runit`. To see which are up, useful when the web UI is slow or 502ing after the container itself reports "running": ```bash ./laradock enter gitlab gitlab-ctl status ``` ```bash docker compose exec gitlab bash gitlab-ctl status ``` ## Common issues - **First page load times out or 502s.** GitLab's Omnibus stack takes several minutes to fully initialize on first boot. Run `./laradock logs gitlab` until it reports it's ready, or check `gitlab-ctl status` inside the container to see which internal service is still starting. - **Can't log in as root.** Use `GITLAB_ROOT_PASSWORD` (default `laradock`). If you changed it after the data volume was already initialized, the change won't retroactively apply, [reset the password](#reset-the-root-password) from inside the container instead. - **Database connection errors on first boot.** Confirm `postgres` is running and that `GITLAB_POSTGRES_INIT=true` in `postgres/defaults.env` so the `laradock_gitlab` database and user get created automatically. - **Wrong clone URLs or broken webhooks.** `GITLAB_DOMAIN_NAME` is still `http://localhost` or doesn't match how you actually access GitLab; update it and restart with `./laradock restart gitlab`. - **Port already in use on your host.** Change `GITLAB_HOST_HTTP_PORT`, `GITLAB_HOST_HTTPS_PORT`, or `GITLAB_HOST_SSH_PORT` in `.env` and restart: `./laradock restart gitlab`. --- Need CI runners to execute your `.gitlab-ci.yml` pipelines? See **[GitLab Runner](https://laradock.io/docs/services/gitlab-runner)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Theia IDE Source: https://laradock.io/docs/services/ide-theia ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Theia? [Theia](https://theia-ide.org) is an open-source, browser-based IDE with a VS Code-like editor, integrated terminal, and extension system. Running it in a container gives you a full development environment reachable from any browser, useful for remote work, pairing, or coding from a machine without your usual local setup. Laradock builds it from the official `theiaide/theia` image. ## Start Theia ```bash ./laradock start ide-theia ``` ```bash docker compose up -d ide-theia ``` Open [http://localhost:987](http://localhost:987) (or your custom `IDE_THEIA_PORT`). `${APP_CODE_PATH_HOST}` is mounted into the container at `/home/project`, so Theia opens the same project code the rest of your Laradock containers work with. `ide-theia/Dockerfile` also raises `fs.inotify.max_user_watches` to `524288` as root before switching back to the `theia` user, this avoids file-watcher errors ("ENOSPC") on projects with a large number of files. ## Stop Theia Stopping just pauses the container: ```bash ./laradock stop ide-theia ``` ```bash docker compose stop ide-theia ``` The editor state itself isn't stored in a Laradock-managed volume, only your project files (via `APP_CODE_PATH_HOST`) persist independently of the container, so there's nothing to lose by stopping or removing it. To delete the container entirely: ```bash ./laradock remove ide-theia ``` ```bash docker compose rm -sf ide-theia ``` ## Configuration All settings live in `ide-theia/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `IDE_THEIA_PORT` | `987` | Host-side port Theia is published on (`host:3000`, Theia listens on `3000` inside the container). | ## Rebuild after changing the Dockerfile `ide-theia/Dockerfile` is a thin wrapper on top of `theiaide/theia`. If you edit it, for example to add a system package or a Theia extension, rebuild the image for the change to take effect: ```bash ./laradock rebuild ide-theia ``` ```bash docker compose build ide-theia ``` There's no `IDE_THEIA_VERSION` variable, the image always builds from `theiaide/theia:latest` as pinned in the Dockerfile's `FROM` line. To pick up upstream Theia updates, rebuild with `--no-cache` (`docker compose build --no-cache ide-theia`) so Docker re-pulls the base image instead of reusing a cached layer. ## View logs If the page won't load or the editor gets stuck, check the container's startup output: ```bash ./laradock logs ide-theia ``` ```bash docker compose logs --tail=100 ide-theia ``` ## Open a terminal inside the container Theia ships its own in-browser terminal once it's loaded, but if the UI itself isn't coming up, get a shell directly to inspect the container: ```bash ./laradock enter ide-theia ``` ```bash docker compose exec ide-theia bash ``` ## Security: no built-in authentication Theia, as run here, has **no login screen and no access control** of its own, whoever can reach `IDE_THEIA_PORT` gets a full editor and terminal on your mounted project code. That's fine on `localhost`, but if you ever expose this container beyond your own machine (a shared dev box, a port forwarded through a tunnel, a cloud VM), put it behind something that authenticates first, for example an nginx vhost with basic auth or a VPN, never publish `IDE_THEIA_PORT` directly to the open internet. ## Common issues - **Port already in use on your host.** Another service (or another Laradock project) is already bound to `987`. Change `IDE_THEIA_PORT` in `.env` and run `./laradock restart ide-theia`. - **File-watcher / "too many open files" errors on large projects.** The Dockerfile already raises `fs.inotify.max_user_watches`, but this setting is applied inside the container's own namespace; on some Docker Desktop setups the host's inotify limit still applies. Raise the host limit too if you keep hitting it. - **Editing files but no changes showing up in other containers.** Confirm `APP_CODE_PATH_HOST` in `.env` points at the same project folder that `php-fpm`/`nginx`/etc. use, Theia only sees whatever is mounted to `/home/project`. - **Blank page or connection refused.** Give the container a few seconds after `./laradock start ide-theia`; check `./laradock logs ide-theia` for startup errors before assuming it's a port issue. --- Need an API spec editor instead of a full IDE? See **[Swagger Editor](https://laradock.io/docs/services/swagger-editor)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Jenkins Source: https://laradock.io/docs/services/jenkins ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Jenkins? [Jenkins](https://www.jenkins.io) is a widely used open-source automation server for building CI/CD pipelines: running tests, building artifacts, and deploying on every push. Laradock runs it as its own privileged container with access to the Docker socket, so pipeline jobs can build and run other containers. ## Start Jenkins ```bash ./laradock start jenkins ``` ```bash docker compose up -d jenkins ``` Jenkins state is created on first start under `JENKINS_HOME` and kept between restarts. ## Stop Jenkins Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop jenkins ``` ```bash docker compose stop jenkins ``` To delete the container entirely (the data on disk is still untouched, it lives under `JENKINS_HOME`): ```bash ./laradock remove jenkins ``` ```bash docker compose rm -sf jenkins ``` ## Logs ```bash ./laradock logs jenkins ``` ```bash docker compose logs --tail=100 jenkins ``` ## Configuration All settings live in `jenkins/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `JENKINS_HOST_HTTP_PORT` | `8090` | Host-side port the Jenkins web UI is published on. | | `JENKINS_HOST_SLAVE_AGENT_PORT` | `50000` | Host-side port for Jenkins build agents (JNLP). | | `JENKINS_HOME` | `./jenkins/jenkins_home` | Host folder mounted to `/var/jenkins_home`, holds all jobs, plugins, and config. | The container also runs `privileged: true` and mounts `/var/run/docker.sock`, so Jenkins jobs can build and run Docker containers directly. ## Initial setup 1. Start the container, then open [http://localhost:8090/](http://localhost:8090/) (or your `JENKINS_HOST_HTTP_PORT`). 2. Sign in with user `admin` and the auto-generated password: ```bash ./laradock exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword ``` ```bash docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword ``` 3. Install the suggested plugins and create your own admin user when prompted. ## Admin tasks Enter the container as **root** (needed for some plugin installs or system packages, no friendly CLI shortcut for the root user, use Docker Compose directly): ```bash docker compose exec --user root jenkins bash ``` For a regular (non-root) shell instead, use the standard `enter` verb: ```bash ./laradock enter jenkins ``` ```bash docker compose exec jenkins bash ``` - Add a user manually at [http://localhost:8090/securityRealm/addUser](http://localhost:8090/securityRealm/addUser). - Review or lock down authorization at [http://localhost:8090/configureSecurity/](http://localhost:8090/configureSecurity/). - Restart Jenkins itself (without restarting the container) at [http://localhost:8090/restart](http://localhost:8090/restart). ## Change the Jenkins version The bundled Jenkins version isn't an `.env` variable, it's baked into the image via build args in `jenkins/Dockerfile`: `JENKINS_VERSION` (currently `2.469`) and `JENKINS_SHA`, the matching `.war` checksum used to verify the download. To bump it: 1. Look up the new version's `.war` SHA-256 checksum from the [Jenkins download site](https://www.jenkins.io/download/) or its release changelog. 2. Update `ARG JENKINS_VERSION` and `ARG JENKINS_SHA` in `jenkins/Dockerfile`. 3. Rebuild: ```bash ./laradock rebuild jenkins ``` ```bash docker compose build jenkins ``` 4. Restart the container: `./laradock restart jenkins`. Your jobs, plugins, and config under `JENKINS_HOME` carry over as-is, Jenkins runs its own plugin-compatibility checks on the new version at startup. ## Backup and restore `JENKINS_HOME` (`./jenkins/jenkins_home` by default) is a plain host folder, not a named Docker volume, so backing it up is just archiving that folder. Stop the container first so nothing is mid-write: ```bash ./laradock stop jenkins ``` ```bash docker compose stop jenkins ``` ```bash tar -czf jenkins-backup.tar.gz -C jenkins jenkins_home ./laradock start jenkins ``` To restore, stop Jenkins, extract the archive back over `jenkins/jenkins_home` (or point `JENKINS_HOME` at wherever you extracted it), then start again: ```bash ./laradock stop jenkins rm -rf jenkins/jenkins_home tar -xzf jenkins-backup.tar.gz -C jenkins ./laradock start jenkins ``` This is also how you move a Jenkins setup (jobs, plugins, credentials, build history) between machines. ## Start completely fresh (wipe all data) To throw away every job, plugin, and credential and start Jenkins from a clean, empty state (this **permanently deletes** everything under `JENKINS_HOME`, back up first if you need anything): ```bash ./laradock stop jenkins ./laradock remove jenkins rm -rf "${JENKINS_HOME:-./jenkins/jenkins_home}" ./laradock start jenkins ``` ```bash docker compose stop jenkins docker compose rm -sf jenkins rm -rf "${JENKINS_HOME:-./jenkins/jenkins_home}" docker compose up -d jenkins ``` Starting again re-runs the full first-boot setup wizard, including a brand-new `initialAdminPassword`. ## Common issues - **Can't find the initial admin password.** It only exists before the setup wizard finishes; run the `./laradock exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword` command above right after first start. - **Port `8090` already in use.** Another local service is bound to it. Change `JENKINS_HOST_HTTP_PORT` in `.env` and restart: `./laradock restart jenkins`. - **Jobs that build Docker images fail.** Confirm the job actually has access to `/var/run/docker.sock` (mounted by default) and that the container is still running `privileged: true`. - **Losing jobs/plugins between rebuilds.** Everything Jenkins-specific lives under `JENKINS_HOME` on your host; don't delete that folder unless you intend to [reset Jenkins entirely](#start-completely-fresh-wipe-all-data). - **Build agents can't connect (JNLP).** Confirm `JENKINS_HOST_SLAVE_AGENT_PORT` is reachable from the agent and matches the port Jenkins itself is configured to use under **Manage Jenkins β†’ Configure Global Security**. --- Need a full CI/CD pipeline with its own Git server instead? See **[GitLab](https://laradock.io/docs/services/gitlab)** or **[OneDev](https://laradock.io/docs/services/onedev)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # OneDev Source: https://laradock.io/docs/services/onedev ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is OneDev? [OneDev](https://onedev.io) is a self-hosted Git server with built-in CI/CD pipelines and issue tracking, packaged as a single container with no external database dependency. Laradock runs it standalone, unlike GitLab it doesn't need `postgres` or `redis`. ## Start OneDev ```bash ./laradock start onedev ``` ```bash docker compose up -d onedev ``` ## Stop OneDev This stops the container without deleting its data. OneDev's state lives under `DATA_PATH_HOST/onedev` on your host. ```bash ./laradock stop onedev ``` ```bash docker compose stop onedev ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/onedev`): ```bash ./laradock remove onedev ``` ```bash docker compose rm -sf onedev ``` ## Configuration All settings live in `onedev/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `ONEDEV_HTTP_PORT` | `6610` | Host-side port for the OneDev web UI. | | `ONEDEV_SSH_PORT` | `6611` | Host-side port for Git-over-SSH. | The `onedev/compose.yml` image tag is unpinned (`1dev/server`, no version suffix), so `./laradock rebuild onedev` always pulls whatever is currently tagged `latest` on Docker Hub, there's no `ONEDEV_VERSION` variable to pin a specific release. ## Complete the setup wizard 1. Start the container, then open [http://localhost:6610](http://localhost:6610). 2. Follow the setup wizard to create your admin account. Git over SSH is available on port `6611` by default; clone with `ssh://git@localhost:6611/`. ## Docker-based CI/CD jobs `onedev/compose.yml` mounts `/var/run/docker.sock` from your host into the container, so OneDev's build agent can launch job containers directly on your **host's** Docker engine (the same pattern Jenkins and GitLab runners use). To use it, add a Docker executor under **Administration β†’ Job Executors** in the OneDev UI, pointing it at the mounted socket. Because those job containers run on the host engine, they are **not** on Laradock's internal Docker network, a job can't reach another Laradock service by its container name (`mysql`, `redis`, etc.); use `host.docker.internal` and the service's published host port instead. ## Backup and restore OneDev keeps everything, its embedded database, repositories, and search index, under a single directory: `DATA_PATH_HOST/onedev` (mounted to `/opt/onedev` in the container). The safest way to back it up is a filesystem copy while the container is stopped, so nothing is mid-write: ```bash ./laradock stop onedev ``` ```bash docker compose stop onedev ``` ```bash tar -czf onedev-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" onedev ``` **Restore** by stopping the container, clearing the target folder, extracting the archive back into place, then starting again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/onedev" tar -xzf onedev-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" ``` ```bash ./laradock start onedev ``` ```bash docker compose up -d onedev ``` ## Start completely fresh (wipe all data) To throw away everything, repositories, issues, CI/CD configuration, the admin account, and start OneDev from a clean, empty state (⚠️ this **permanently deletes** all of it, back up first if you need anything): ```bash ./laradock stop onedev ./laradock remove onedev rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/onedev" ./laradock start onedev ``` ```bash docker compose stop onedev docker compose rm -sf onedev rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/onedev" docker compose up -d onedev ``` Starting again re-runs the setup wizard from scratch, including creating a new admin account. ## Common issues - **Port `6610` or `6611` already in use.** Change `ONEDEV_HTTP_PORT` or `ONEDEV_SSH_PORT` in `.env` and restart: `./laradock restart onedev`. - **First page load is slow.** OneDev initializes its embedded database and search index on first boot; give it a minute and check `./laradock logs onedev`. - **SSH clone fails.** Confirm you're using the mapped host port (`ONEDEV_SSH_PORT`, `6611` by default), not the container-internal `6611` if you've remapped it, and that your SSH key is added in OneDev's user settings. - **CI/CD jobs can't reach another Laradock service.** Docker-executor jobs run on your host's Docker engine, not Laradock's internal network, see [Docker-based CI/CD jobs](#docker-based-cicd-jobs) above. --- Need CI/CD without a bundled Git server instead? See **[Jenkins](https://laradock.io/docs/services/jenkins)**. Prefer a fuller-featured self-hosted GitHub alternative? See **[GitLab](https://laradock.io/docs/services/gitlab)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Portainer Source: https://laradock.io/docs/services/portainer ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Portainer? [Portainer](https://www.portainer.io) is a web-based UI for managing Docker: containers, images, volumes, networks, and logs, all from a browser instead of the CLI. Laradock runs it with access to the host's Docker socket so it can manage the whole stack, including containers outside Laradock itself. ## Start Portainer ```bash ./laradock start portainer ``` ```bash docker compose up -d portainer ``` ## Create your admin account (first run) Open [http://localhost:9010](http://localhost:9010) right after starting the container. Portainer makes you set the initial admin username and password on this very first visit, there's no default login to look up. This window is time-limited: if you don't finish creating the admin account within a few minutes of the container's first boot, Portainer disables the setup endpoint for security and refuses to let you create one, showing an error instead of the setup form. If that happens, [start completely fresh](#start-completely-fresh-wipe-all-data) (or just recreate the container if you haven't put anything in it yet) and complete the setup form promptly this time. ## Stop Portainer Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop portainer ``` ```bash docker compose stop portainer ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove portainer ``` ```bash docker compose rm -sf portainer ``` Portainer's own state (admin account, users, settings, registered endpoints) lives under `DATA_PATH_HOST/portainer_data` on your host, so removing the container alone doesn't lose anything. ## Configuration Portainer has no `defaults.env` file of its own, it isn't parameterized per-service in Laradock. It uses the shared top-level settings from the root `.env`: | Variable | Default | What it does | |---|---|---| | `DATA_PATH_HOST` | `~/.laradock/data` | Host folder for all Laradock data volumes; Portainer's state lives at `DATA_PATH_HOST/portainer_data`. | | `DOCKER_HOST_IP` | `10.0.75.1` | Added as an `extra_hosts` entry (`dockerhost`) so the container can reach services running directly on your host. | The published port (`9010` on the host, mapping to `9000` in the container) is hardcoded in `portainer/compose.yml`, not driven by an env var. To change it, edit the `ports:` line in that file directly. Portainer is mounted with `/var/run/docker.sock`, which gives it full control over your Docker daemon, effectively root-equivalent access to the host. That's what lets it manage every container, not just Laradock's, so treat the dashboard with the same care as root access to your machine. ## Backup and restore Everything Portainer knows (admin account, users, endpoints, stack definitions saved in the UI) lives entirely in `DATA_PATH_HOST/portainer_data`, there's no database to dump. **Back it up** by copying that folder while the container is stopped, so nothing is mid-write: ```bash ./laradock stop portainer ``` ```bash docker compose stop portainer ``` ```bash tar -czf portainer-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" portainer_data ``` **Restore** by extracting that archive back into the same location (with the container stopped) before starting it again: ```bash tar -xzf portainer-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" ``` ## Start completely fresh (wipe all data) To throw away every Portainer setting and go back to a blank first-run state (⚠️ this **permanently deletes** your admin account, users, and any saved endpoints/stacks, back up first if you need anything): ```bash ./laradock stop portainer ./laradock remove portainer rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/portainer_data" ./laradock start portainer ``` ```bash docker compose stop portainer docker compose rm -sf portainer rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/portainer_data" docker compose up -d portainer ``` Starting it back up drops you into the [first-run admin setup](#create-your-admin-account-first-run) again. ## Pin a specific Portainer version `portainer/Dockerfile` builds from `portainer/portainer` with no tag, which tracks whatever `latest` currently points to. To pin a version instead, edit the `FROM` line, for example: ```dockerfile FROM portainer/portainer-ce:2.19.4 ``` Then apply it: ```bash ./laradock rebuild portainer ``` ```bash docker compose build portainer ``` ## Common issues - **Port `9010` already in use.** Since the port isn't controlled by an env var, edit the `ports:` mapping in `portainer/compose.yml` directly, then `./laradock start portainer`. - **"Setup expired" / can't create the admin account.** You didn't finish the [first-run setup form](#create-your-admin-account-first-run) in time. [Start completely fresh](#start-completely-fresh-wipe-all-data) and complete it promptly. - **Portainer can't see other containers.** It needs `/var/run/docker.sock` mounted (this is the default in `portainer/compose.yml`); confirm that mount wasn't removed. - **Can't reach services running on your host machine from inside Portainer.** Confirm `DOCKER_HOST_IP` in `.env` matches your actual host IP for your OS/Docker setup (defaults assume Docker Desktop's typical gateway). - **Lost dashboard settings after recreating the container.** Data persists in `DATA_PATH_HOST/portainer_data`; if you changed `DATA_PATH_HOST` or wiped that folder, Portainer starts fresh and asks you to create a new admin account. --- Prefer managing containers straight from the terminal? See the **[Getting Started](https://laradock.io/docs/getting-started)** guide for core `docker compose` commands. ================================================================ # SonarQube Source: https://laradock.io/docs/services/sonarqube ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is SonarQube? [SonarQube](https://docs.sonarqube.org/latest/) is an automatic code-review tool that scans your codebase for bugs, vulnerabilities, and code smells across branches and pull requests. Laradock runs it as its own container, backed by the `postgres` service already in the stack. ## Start SonarQube ```bash ./laradock start sonarqube ``` ```bash docker compose up -d sonarqube ``` SonarQube depends on `postgres` (declared in `sonarqube/compose.yml`), Compose starts it automatically. First boot takes a minute or two while SonarQube's embedded Elasticsearch index initializes, watch `./laradock logs sonarqube` for `SonarQube is operational` before opening the UI. ## Stop SonarQube Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop sonarqube ``` ```bash docker compose stop sonarqube ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/sonarqube`): ```bash ./laradock remove sonarqube ``` ```bash docker compose rm -sf sonarqube ``` ## Configuration All settings live in `sonarqube/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `SONARQUBE_HOSTNAME` | `sonar.example.com` | Hostname the container identifies itself as; set it to your real domain. | | `SONARQUBE_PORT` | `9000` | Host-side port SonarQube is published on. | | `SONARQUBE_POSTGRES_HOST` | `postgres` | Hostname of the Postgres container SonarQube connects to. | SonarQube also needs `SONARQUBE_POSTGRES_USER`, `SONARQUBE_POSTGRES_PASSWORD`, and `SONARQUBE_POSTGRES_DB` to create its database in Postgres. These aren't in `sonarqube/defaults.env`, they ship as top-level defaults in `.env.example` (`sonar` / `sonarPass` / `sonar`). The `postgres` service also needs `SONARQUBE_POSTGRES_INIT=true` (set by default in `postgres/defaults.env`) to auto-create that database and user on its first boot. ## Initial admin setup The first-run confusion point with SonarQube: it ships with a default login of **`admin` / `admin`**, and the UI forces you to set a new password the first time you sign in at [http://localhost:9000/](http://localhost:9000/) (`SONARQUBE_PORT`). There's no separate "unlock" file to hunt down like Jenkins, just log in once with the defaults and follow the prompt. ## Run your first scan SonarQube only reviews code you actively send it. From your project's root: 1. Log in to the UI, then go to **My Account β†’ Security β†’ Generate Tokens** to create an analysis token. 2. Run [`sonar-scanner`](https://docs.sonarqube.org/latest/analyzing-source-code/scanners/sonarscanner/) against this instance (install it on your host or inside `./laradock workspace` if your project doesn't already ship one via a build tool plugin): ```bash sonar-scanner \ -Dsonar.projectKey=my-project \ -Dsonar.sources=. \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login= ``` Swap `http://localhost:9000` for `SONARQUBE_HOSTNAME`'s address if you changed it, and `` for the token from step 1. Results show up under the project's dashboard in the UI once the scan finishes. ## Set your hostname ```env SONARQUBE_HOSTNAME=sonar.example.com ``` Set this to your actual domain before exposing SonarQube beyond local dev. `SONARQUBE_HOSTNAME` is baked into the container at creation time (it's the Compose `hostname:` field), so a plain restart won't pick it up, rebuild and recreate the container: ```bash ./laradock rebuild sonarqube ./laradock start sonarqube ``` ```bash docker compose build sonarqube docker compose up -d sonarqube ``` Then open [http://localhost:9000/](http://localhost:9000/). ## Backup and restore SonarQube's real state (projects, analysis history, quality gates, users) lives in its Postgres database, not in the container itself. Back that up with `pg_dump` against the `postgres` service: ```bash ./laradock exec -T postgres pg_dump -U sonar sonar > sonarqube-backup.sql ``` ```bash docker compose exec -T postgres pg_dump -U sonar sonar > sonarqube-backup.sql ``` Swap `sonar`/`sonar` for your own `SONARQUBE_POSTGRES_USER`/`SONARQUBE_POSTGRES_DB` if you changed them. The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file, always include it when piping output to or from a file. Restore it into an existing SonarQube database: ```bash ./laradock exec -T postgres psql -U sonar sonar < sonarqube-backup.sql ``` ```bash docker compose exec -T postgres psql -U sonar sonar < sonarqube-backup.sql ``` Plugins, custom quality profiles stored on disk, and logs live under `DATA_PATH_HOST/sonarqube/{extensions,plugins,conf,logs}`, copy that folder alongside the database dump if you rely on custom plugins. ## Start completely fresh (wipe all data) `postgres` is shared with other services (Confluence, GitLab, Keycloak), so wiping its whole data folder would take those down too. To reset **only** SonarQube, drop its database and its own data folders instead: ```bash ./laradock stop sonarqube ./laradock remove sonarqube rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/sonarqube" ./laradock exec postgres psql -U postgres -c "DROP DATABASE sonar;" ./laradock exec postgres psql -U postgres -c "CREATE DATABASE sonar OWNER sonar;" ./laradock start sonarqube ``` ```bash docker compose stop sonarqube docker compose rm -sf sonarqube rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/sonarqube" docker compose exec postgres psql -U postgres -c "DROP DATABASE sonar;" docker compose exec postgres psql -U postgres -c "CREATE DATABASE sonar OWNER sonar;" docker compose up -d sonarqube ``` ⚠️ This **permanently deletes** every project, analysis history, and user in this SonarQube instance, back up first if you need anything. `postgres -U postgres` assumes the default superuser from `postgres/defaults.env`, swap it for your own `POSTGRES_USER` if you changed it. SonarQube re-runs its first-boot database migration on the next start, exactly like a brand-new install. ## Talk to this SonarQube from another Laradock project Since `SONARQUBE_PORT` is published to your host, another project's CI tooling (a second Laradock's Jenkins or GitLab Runner, or a native CI pipeline) can point at this same instance instead of spinning up its own. From outside this project, target your **host machine's** address on `SONARQUBE_PORT`, for example `sonar.host.url=http://host.docker.internal:9000` from another container (Docker Desktop), or `http://localhost:9000` from the host itself. Give each project a distinct `sonar.projectKey` so their scans don't overwrite each other's dashboards. ## Common issues - **Elasticsearch fails to start / container exits on boot.** SonarQube's embedded Elasticsearch needs `vm.max_map_count` set to at least `262144` on the Docker **host**, not just the container. On Linux, run `sudo sysctl -w vm.max_map_count=262144` (add it to `/etc/sysctl.conf` to persist); on Docker Desktop (macOS/Windows) this is usually already high enough, but if you still see `max virtual memory areas vm.max_map_count` in `./laradock logs sonarqube`, increase it in Docker Desktop's resources settings. - **Database connection error.** Postgres wasn't initialized with the SonarQube database, or its init script needs a manual re-run as root inside the `postgres` container: ```bash docker compose exec --user=root postgres bash source docker-entrypoint-initdb.d/init_sonarqube_db.sh ``` - **SonarQube fails to start with a logs permission error.** Fix ownership on the mounted logs folder: ```bash docker compose run --user=root --rm sonarqube chown sonarqube:sonarqube /opt/sonarqube/logs ``` - **Port `9000` already in use.** Another local service is bound to it (this also collides with Minio's default port if you run both). Change `SONARQUBE_PORT` in `.env` and restart: `./laradock restart sonarqube`. - **Changing `SONARQUBE_HOSTNAME` has no effect.** It's baked in at container creation, see [Set your hostname](#set-your-hostname) above, a plain restart isn't enough. --- Need CI to run SonarQube scans automatically? See **[Jenkins](https://laradock.io/docs/services/jenkins)** or **[GitLab Runner](https://laradock.io/docs/services/gitlab-runner)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Swagger Editor Source: https://laradock.io/docs/services/swagger-editor ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Swagger Editor? [Swagger Editor](https://github.com/swagger-api/swagger-editor) is a browser-based editor for writing OpenAPI (formerly Swagger) API specifications in YAML or JSON, with live syntax validation and a preview of the rendered documentation as you type. Laradock builds it from the official `swaggerapi/swagger-editor` image. ## Start Swagger Editor ```bash ./laradock start swagger-editor ``` ```bash docker compose up -d swagger-editor ``` Open [http://localhost:5151](http://localhost:5151) (or your custom `SWAGGER_EDITOR_PORT`) and start writing your OpenAPI spec. `swagger-editor/compose.yml` doesn't mount any host folder into the container, so specs you write live in the browser's own storage (or wherever you manually export them to), not on disk in your project. ## Stop Swagger Editor ```bash ./laradock stop swagger-editor ``` ```bash docker compose stop swagger-editor ``` To delete the container entirely (there's no data volume to worry about, since nothing on disk belongs to this service): ```bash ./laradock remove swagger-editor ``` ```bash docker compose rm -sf swagger-editor ``` ## Configuration All settings live in `swagger-editor/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SWAGGER_EDITOR_PORT` | `5151` | Host-side port Swagger Editor is published on (`host:8080`, the editor listens on `8080` inside the container). | ## Importing and exporting your spec Since nothing is persisted to disk by Laradock, the spec you're editing only exists in the browser tab until you explicitly save it somewhere. Use the editor's own **File** menu to: - **Import File** or **Import URL** to load an existing spec (YAML or JSON) into the editor. - **Download YAML** / **Download JSON** to save your current spec back to your machine, or into your project's own repo so it's tracked in git. Treat the running container as a scratchpad, not storage: always download before closing the tab or restarting the container. ## Update to the latest image `swagger-editor/Dockerfile` builds from `swaggerapi/swagger-editor:latest`, so Docker will keep reusing whatever image layer you already have cached, it won't fetch a newer `latest` on its own. To pull the newest upstream release and rebuild: ```bash docker pull swaggerapi/swagger-editor:latest docker compose build --no-cache swagger-editor ``` Then start it again with the `Start Swagger Editor` command above. ## Common issues - **Port already in use on your host.** Another service (or another Laradock project) is already bound to `5151`. Change `SWAGGER_EDITOR_PORT` in `.env` and restart with `./laradock restart swagger-editor`. - **Spec disappears after closing the browser tab or restarting the container.** Nothing is persisted to your project files by default, since there's no volume mount in `swagger-editor/compose.yml`. Export/download your spec from the editor's UI regularly, or edit spec files in your own project and paste them in. - **Blank page or connection refused.** Give the container a few seconds after starting; check `./laradock logs swagger-editor` for startup errors. --- Want to render a finished spec as interactive docs instead of editing it? See **[Swagger UI](https://laradock.io/docs/services/swagger-ui)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Swagger UI Source: https://laradock.io/docs/services/swagger-ui ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Swagger UI? [Swagger UI](https://github.com/swagger-api/swagger-ui) renders an OpenAPI (formerly Swagger) specification as interactive, browsable API documentation, complete with a "try it out" panel for firing real requests at your API. Laradock builds it from the official `swaggerapi/swagger-ui` image. ## Start Swagger UI ```bash ./laradock start swagger-ui ``` ```bash docker compose up -d swagger-ui ``` Swagger UI is stateless, it doesn't store any data of its own, it just renders whatever spec `SWAGGER_API_URL` points at. ## Stop Swagger UI ```bash ./laradock stop swagger-ui ``` ```bash docker compose stop swagger-ui ``` To delete the container entirely (nothing to lose, there's no data volume): ```bash ./laradock remove swagger-ui ``` ```bash docker compose rm -sf swagger-ui ``` ## Configuration All settings live in `swagger-ui/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `SWAGGER_API_URL` | `http://generator.swagger.io/api/swagger.json` | The URL Swagger UI fetches its OpenAPI spec from, passed into the container as the `API_URL` environment variable. | | `SWAGGER_UI_PORT` | `5555` | Host-side port Swagger UI is published on (`host:8080`, the UI listens on `8080` inside the container). | ## Point it at your own API spec ```env SWAGGER_API_URL=http://your-app.test/api/openapi.json ``` ```bash ./laradock restart swagger-ui ``` ```bash docker compose up -d swagger-ui ``` Open [http://localhost:5555](http://localhost:5555) (or your custom `SWAGGER_UI_PORT`). `SWAGGER_API_URL` must be reachable from inside the `swagger-ui` container, so if your spec is served by another Laradock container, use its container name (for example `http://nginx/api/openapi.json`) rather than `localhost`. ## View logs Useful when the UI shows a blank page or a spec fails to load: ```bash ./laradock logs swagger-ui ``` ```bash docker compose logs --tail=100 swagger-ui ``` ## Keep the image up to date Laradock builds Swagger UI `FROM swaggerapi/swagger-ui:latest`. Docker only pulls the `latest` tag the first time it's built, a plain rebuild reuses whatever was already pulled and won't fetch newer releases. To actually pull the newest upstream image and rebuild against it: ```bash docker compose build --pull swagger-ui ``` Then start the container again with your normal `./laradock start swagger-ui` (or `docker compose up -d swagger-ui`). ## Common issues - **Still showing the default demo spec.** `SWAGGER_API_URL` only takes effect on container start. Set it in `.env` and run `./laradock restart swagger-ui` to apply it. - **"Failed to fetch" when loading your spec.** If your API lives in another Laradock container, `localhost` from inside `swagger-ui` refers to the `swagger-ui` container itself, not your host or your API container. Use the API's container name instead (Laradock containers share the `backend` network). - **CORS errors in the browser console.** Swagger UI fetches the spec client-side from your browser, not just server-side, so your API must also send CORS headers allowing the origin `http://localhost:5555` (or your custom port). - **Port already in use on your host.** Another service (or another Laradock project) is already bound to `5555`. Change `SWAGGER_UI_PORT` in `.env` and restart with `./laradock restart swagger-ui`. - **Image never picks up a newer Swagger UI release.** See [Keep the image up to date](#keep-the-image-up-to-date) above, `latest` is only resolved once unless you explicitly `--pull`. --- Writing the spec by hand? See **[Swagger Editor](https://laradock.io/docs/services/swagger-editor)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Supported Services Source: https://laradock.io/docs/supported-services ================================================================ import HubCardList from '@site/src/components/HubCardList'; Laradock ships dozens of services as pre-configured containers: databases, caches and queues, search engines, web servers, mail catchers, AI/ML stacks, monitoring, and developer tools. You don't install any of them on your machine, they run in Docker, isolated and disposable. ## Enable only what you need Nothing runs until you ask for it. You name the services you want when you start Laradock, and only those containers come up: ```bash ./laradock start nginx mysql redis ``` Need Postgres and Elasticsearch on a different project? Start those instead. Your host machine stays clean, and two projects can use completely different stacks without conflicting. ## Configured, not just installed Each service comes wired into the Laradock network with sane defaults, the workspace container can already reach `mysql`, `redis`, and the rest by hostname, and credentials live in one `.env` file. The per-service guides below cover the specifics: default ports, how to connect from your app, and the settings worth changing. ## Browse by category ================================================================ # MailCatcher Source: https://laradock.io/docs/services/mailcatcher ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MailCatcher? [MailCatcher](https://mailcatcher.me) is a Ruby-based SMTP testing tool and one of the original tools in this space, it runs a fake SMTP server that catches outgoing dev email and shows it in a web UI instead of delivering it. Laradock builds it from the `schickling/mailcatcher` image. ## Start MailCatcher ```bash ./laradock start mailcatcher ``` ```bash docker compose up -d mailcatcher ``` ## Stop MailCatcher ```bash ./laradock stop mailcatcher ``` ```bash docker compose stop mailcatcher ``` This stops the container without touching anything on disk. To remove the container: ```bash ./laradock remove mailcatcher ``` ```bash docker compose rm -sf mailcatcher ``` Either way, all captured mail is gone once the container stops, see [Captured mail is not persisted](#captured-mail-is-not-persisted-by-design) below. ## Configuration MailCatcher has no `defaults.env`, its ports are fixed directly in `mailcatcher/compose.yml`: | Port | Purpose | |---|---| | `1025` | SMTP, point your app's mail driver here. | | `1080` | Web UI, browse caught mail here. | Because these are hardcoded (`"1025:1025"` and `"1080:1080"`), there's no `MAILCATCHER_*_PORT` variable to override in `.env`. The container runs `mailcatcher --no-quit --foreground --ip=0.0.0.0` (set in `mailcatcher/Dockerfile`), so it listens on all interfaces inside the container. ## Connect your app Open the web UI at [http://localhost:1080](http://localhost:1080). Point your app's SMTP settings at the `mailcatcher` container name (not `localhost`) on port `1025`: ```env MAIL_MAILER=smtp MAIL_HOST=mailcatcher MAIL_PORT=1025 MAIL_USERNAME=null MAIL_PASSWORD=null ``` ## Clear captured mail Click **Clear** in the top-right of the web UI to delete every caught message, or do it from the command line with MailCatcher's own HTTP API: ```bash curl -X DELETE http://localhost:1080/messages ``` ```bash curl -X DELETE http://localhost:1080/messages ``` This hits MailCatcher directly over the published web UI port, it's the same for both columns since it's a plain HTTP call, not a container command. You can also list captured messages as JSON with `curl http://localhost:1080/messages`, useful for asserting on sent mail from a test script. ## Captured mail is not persisted by design MailCatcher has no `compose.yml` volume mount, it keeps every caught message in an in-memory SQLite database inside the container. That means: - Stopping, removing, or rebuilding the container **wipes all captured mail**, there's nothing to back up and nothing to restore. - There's no "start completely fresh" step needed, every fresh start already is one. If you need captured mail to survive container restarts across a longer test run, that's a reason to reach for **[Mailpit](https://laradock.io/docs/services/mailpit)** instead, which persists to a database file on disk. ## Common issues - **Mail isn't showing up in the UI.** Confirm your app's `.env` uses `MAIL_HOST=mailcatcher` (the container name), not `localhost` or `127.0.0.1`, those only resolve from your host machine, not from inside another container. - **Mail I caught yesterday is gone.** Expected, see [Captured mail is not persisted](#captured-mail-is-not-persisted-by-design) above, restarting the container always clears the inbox. - **Port `1025` or `1080` already taken on your host.** MailCatcher's ports aren't configurable via `.env`. Either free the port, or switch to `mailpit` or `maildev`, both of which expose equivalent ports through env vars. - **Looking for something more actively developed.** MailCatcher (the Ruby gem) sees infrequent updates. **[Mailpit](https://laradock.io/docs/services/mailpit)** is a modern, actively maintained alternative with the same core idea. --- Prefer the actively maintained, Go-based alternative? See **[Mailpit](https://laradock.io/docs/services/mailpit)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MailDev Source: https://laradock.io/docs/services/maildev ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MailDev? [MailDev](https://github.com/maildev/maildev) is a simple SMTP testing tool: it catches outgoing dev email and shows it in a web UI instead of delivering it, similar in purpose to [Mailpit](https://laradock.io/docs/services/mailpit) and [MailHog](https://laradock.io/docs/services/mailhog). Laradock builds it as its own container from the official `maildev/maildev` image. ## Start MailDev ```bash ./laradock start maildev ``` ```bash docker compose up -d maildev ``` MailDev keeps no volume on disk, everything it catches lives in the container's memory only. That's fine for day-to-day dev testing, just know that stopping or removing the container discards every captured email (see [Clear captured mail](#clear-captured-mail) below if you want to do that on purpose without restarting). ## Stop MailDev Stopping just pauses the container: ```bash ./laradock stop maildev ``` ```bash docker compose stop maildev ``` To remove the container: ```bash ./laradock remove maildev ``` ```bash docker compose rm -sf maildev ``` Since MailDev has no data volume, stopping or removing it has the same practical effect either way: whatever mail was captured is gone once the container isn't running. ## Configuration All settings live in `maildev/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MAILDEV_HTTP_PORT` | `1080` | Host-side port for the web UI (container port `1080`). | | `MAILDEV_SMTP_PORT` | `25` | Host-side port for the SMTP catcher (container port `25`). | ## Connect your app Open the web UI at [http://localhost:1080](http://localhost:1080). Point your app's SMTP settings at the `maildev` container name (not `localhost`) on its internal SMTP port: ```env MAIL_MAILER=smtp MAIL_HOST=maildev MAIL_PORT=25 MAIL_USERNAME=null MAIL_PASSWORD=null ``` ## Clear captured mail MailDev has no "delete all" data-wipe step the way a database would, since it never writes to disk. To clear what's currently showing in the web UI: - **From the UI**: open [http://localhost:1080](http://localhost:1080) and use the trash/delete-all icon in the toolbar to clear every captured message, or delete individual messages from their row. - **From the REST API**: MailDev exposes a small HTTP API on the same port as the web UI. To delete everything: ```bash curl -X DELETE http://localhost:1080/email/all ``` Restarting or removing the container achieves the same result, since nothing is persisted between runs anyway. ## Common issues - **Mail isn't showing up in the UI.** Confirm your app's `.env` uses `MAIL_HOST=maildev` (the container name), not `localhost` or `127.0.0.1`, those only resolve from your host machine, not from inside another container. - **Port `25` conflicts on your host.** Port 25 is often reserved or blocked by ISPs/host mail agents. Change `MAILDEV_SMTP_PORT` in `.env` and restart: `./laradock restart maildev`. - **Port already in use for the web UI.** Change `MAILDEV_HTTP_PORT` in `.env` and restart: `./laradock restart maildev`. - **Captured mail disappeared.** Expected if the container was stopped, removed, or restarted, MailDev keeps everything in memory only, there's no volume backing it. --- Prefer a more actively maintained, Go-based catcher? See **[Mailpit](https://laradock.io/docs/services/mailpit)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MailHog Source: https://laradock.io/docs/services/mailhog ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MailHog? [MailHog](https://github.com/mailhog/MailHog) is an SMTP testing tool that catches outgoing dev email and shows it in a web UI instead of delivering it. It was one of the most widely used dev mail catchers for years, but the project has been effectively unmaintained since 2022. Laradock still ships it for existing setups, but new projects should prefer **[Mailpit](https://laradock.io/docs/services/mailpit)**, a modern, actively maintained, drop-in replacement written in Go. ## Start MailHog ```bash ./laradock start mailhog ``` ```bash docker compose up -d mailhog ``` ## Stop MailHog ```bash ./laradock stop mailhog ``` ```bash docker compose stop mailhog ``` This stops the container without deleting anything. MailHog keeps caught messages **in memory only** (no data volume), so stopping, restarting, or removing the container also clears every caught email, there's nothing on disk to preserve. To remove the container: ```bash ./laradock remove mailhog ``` ```bash docker compose rm -sf mailhog ``` ## Configuration MailHog has no `defaults.env`, its ports are fixed directly in `mailhog/compose.yml`: | Port | Purpose | |---|---| | `1025` | SMTP, point your app's mail driver here. | | `8025` | Web UI, browse caught mail here. | Because these are hardcoded (`"1025:1025"` and `"8025:8025"`), there's no `MAILHOG_*_PORT` variable to override in `.env`. If you need a configurable port, use `mailpit` or `maildev` instead. ## Connect your app Open the web UI at [http://localhost:8025](http://localhost:8025). Point your app's SMTP settings at the `mailhog` container name (not `localhost`) on port `1025`: ```env MAIL_MAILER=smtp MAIL_HOST=mailhog MAIL_PORT=1025 MAIL_USERNAME=null MAIL_PASSWORD=null ``` ## Clear captured mail MailHog has no persistent storage, so any of these throw away everything it has caught so far: - **From the web UI**: open [http://localhost:8025](http://localhost:8025) and click the trash/delete-all button in the top bar. - **Via the HTTP API**, from your host machine: ```bash curl -X DELETE http://localhost:8025/api/v1/messages ``` - **By restarting the container** (same effect, since nothing is written to disk): ```bash ./laradock restart mailhog ``` ```bash docker compose restart mailhog ``` ## Common issues - **Mail isn't showing up in the UI.** Confirm your app's `.env` uses `MAIL_HOST=mailhog` (the container name), not `localhost` or `127.0.0.1`, those only resolve from your host machine, not from inside another container. - **Port `1025` or `8025` already taken on your host.** MailHog's ports aren't configurable via `.env`. Either free the port, or switch to `mailpit` or `maildev`, both of which expose `MAILHOG`-equivalent ports through env vars. - **Caught mail disappeared after a restart.** Expected: MailHog only keeps messages in memory, restarting or recreating the container always clears them. There's nothing to back up or restore. - **Considering MailHog for a new project.** The upstream project is largely dormant. Use **[Mailpit](https://laradock.io/docs/services/mailpit)** instead, same idea, actively maintained, configurable ports. --- Prefer the actively maintained successor? See **[Mailpit](https://laradock.io/docs/services/mailpit)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Mailpit Source: https://laradock.io/docs/services/mailpit ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mailpit? [Mailpit](https://mailpit.axllent.org) is a modern, fast, Go-based SMTP testing tool. It runs a fake SMTP server that catches every email your app sends and shows them in a web UI, instead of actually delivering them. Laradock builds it as its own container so you never accidentally send real email from a dev environment. ## Start Mailpit ```bash ./laradock start mailpit ``` ```bash docker compose up -d mailpit ``` Mailpit keeps caught mail **in memory only**, there's no data volume in its `compose.yml`. Any mail it has caught is gone the moment the container stops or restarts, that's expected, not a bug. ## Stop Mailpit ```bash ./laradock stop mailpit ``` ```bash docker compose stop mailpit ``` This also clears every caught email, since nothing is written to disk. To remove the container as well: ```bash ./laradock remove mailpit ``` ```bash docker compose rm -sf mailpit ``` ## Configuration All settings live in `mailpit/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MAILPIT_HTTP_PORT` | `8125` | Host-side port for the web UI (container port `8025`). | | `MAILPIT_SMTP_PORT` | `1125` | Host-side port for the SMTP catcher (container port `1025`). | ## Connect your app Open the web UI at [http://localhost:8125](http://localhost:8125) to see caught mail. Other containers on the same Laradock network (`workspace`, `php-fpm`, ...) reach Mailpit by its **container name** on its **container-internal** ports, `8025` and `1025`, not the host-side `MAILPIT_HTTP_PORT`/`MAILPIT_SMTP_PORT` values: ```env MAIL_MAILER=smtp MAIL_HOST=mailpit MAIL_PORT=1025 MAIL_USERNAME=null MAIL_PASSWORD=null ``` From your **host machine** (a native mail client, a script outside Docker), use `localhost` and the host-side ports instead: SMTP on `MAILPIT_SMTP_PORT` (`1125`), web UI on `MAILPIT_HTTP_PORT` (`8125`). ## Clear captured mail Click the trash icon in the web UI to delete all messages, or delete them from the command line via Mailpit's REST API: ```bash curl -X DELETE http://localhost:8125/api/v1/messages ``` ```bash curl -X DELETE http://localhost:8125/api/v1/messages ``` This talks to the published web UI port from your host, so the command is identical either way; there's no container-specific form of it. Restarting the container (see [Start Mailpit](#start-mailpit)) achieves the same thing, since caught mail doesn't survive a restart anyway. ## Read caught mail from a test suite Mailpit exposes a JSON API, handy for E2E tests that need to grab a verification code or a magic link out of an email your app just sent, without a human opening the UI: ```bash curl http://localhost:8125/api/v1/messages ``` Each entry includes an `ID` you can pass to `GET /api/v1/message/{ID}` for the full body (HTML/text/headers). See the [Mailpit API docs](https://mailpit.axllent.org/docs/api-cli/view/) for the full schema. From inside another container, use the container-internal address instead: `http://mailpit:8025/api/v1/messages`. ## Common issues - **Mail isn't showing up in the UI.** Confirm your app's `.env` uses `MAIL_HOST=mailpit` (the container name) and `MAIL_PORT=1025` (the container-internal SMTP port), not `localhost`/`MAILPIT_SMTP_PORT`, those only resolve from your host machine, not from inside another container like `workspace` or `php-fpm`. - **Mail I caught yesterday is gone.** Expected: Mailpit only keeps mail in memory. Any `./laradock stop mailpit`, `./laradock restart mailpit`, or host reboot clears it. - **Port already in use on your host.** Change `MAILPIT_HTTP_PORT` (and/or `MAILPIT_SMTP_PORT`) in `.env` and restart: `./laradock restart mailpit`. - **Confusing the two ports.** `MAILPIT_SMTP_PORT` (`1125` by default) is what you send mail to *from your host*; `MAILPIT_HTTP_PORT` (`8125`) is where you view it in a browser *from your host*. Containers on the Laradock network use the container-internal `1025`/`8025` instead, not either of these. --- Looking for the older Go-based tool Mailpit replaced? See **[MailHog](https://laradock.io/docs/services/mailhog)**. Need a full mail server instead of a dev catcher? See **[Mailu](https://laradock.io/docs/services/mailu)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Mailu Source: https://laradock.io/docs/services/mailu ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mailu? [Mailu](https://mailu.io) is a full self-hosted mail server suite: SMTP, IMAP, webmail, antispam, and antivirus, all in one stack. Unlike the other mail services in Laradock (Mailpit, MailHog, MailDev, MailCatcher), which only catch and display outgoing dev email, Mailu is a real mail server capable of sending and receiving actual mail for a domain you control. Laradock wires up the whole Mailu stack as a group of containers. ## Start Mailu ```bash ./laradock start mailu ``` ```bash docker compose up -d mailu ``` `mailu/compose.yml` defines `mailu` as the umbrella service, depending on `mailu-front` (nginx), `mailu-imap` (Dovecot), `mailu-smtp` (Postfix), `mailu-antispam` (rspamd), `mailu-antivirus` (ClamAV), `mailu-webdav`, `mailu-admin`, and `mailu-webmail` (Rainloop by default), plus `mailu-fetchmail`. Starting `mailu` brings up the whole chain automatically. `mailu-admin` also depends on `redis`. ## Stop Mailu Stopping just pauses the containers; **your data is safe**. `depends_on` only cascades on `up`, not `stop`, so every container has to be named explicitly: ```bash ./laradock stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` ```bash docker compose stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` To delete all the containers entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/mailu/`): ```bash ./laradock remove mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` ```bash docker compose rm -sf mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` ## Configuration All settings live in `mailu/defaults.env` and can be overridden by adding the same line to your own `.env`. This is a large suite, so only the most commonly touched settings are listed here, the file has more (DMARC report addresses, welcome-email text, statistics opt-out, password hashing scheme). | Variable | Default | What it does | |---|---|---| | `MAILU_VERSION` | `latest` | Image tag shared by every Mailu container. | | `MAILU_DOMAIN` | `example.com` | Main mail domain. | | `MAILU_HOSTNAMES` | `mail.example.com,alternative.example.com,yetanother.example.com` | Comma-separated hostnames this server answers to. | | `MAILU_POSTMASTER` | `admin` | Local part of the postmaster address (`postmaster@`+`MAILU_DOMAIN`). | | `MAILU_HTTP_PORT` | `6080` | Host-side port for the web admin/webmail (container port `80`). | | `MAILU_HTTPS_PORT` | `60443` | Host-side port for HTTPS (container port `443`). | | `MAILU_WEB_ADMIN` | `/admin` | URL path the admin interface is served under. | | `MAILU_WEB_WEBMAIL` | `/webmail` | URL path the webmail client is served under. | | `MAILU_INIT_ADMIN_USERNAME` | `laradock` | Username for the admin account created on first boot. | | `MAILU_INIT_ADMIN_PASSWORD` | `laradock` | Password for that admin account. | | `MAILU_SECRET_KEY` | `ChangeMeChangeMe` | Random 16-byte secret used internally; change this before any real use. | | `MAILU_TLS_FLAVOR` | `cert` | TLS mode: `letsencrypt`, `cert`, `notls`, or `mail`. | | `MAILU_MESSAGE_SIZE_LIMIT` | `50000000` | Max accepted message size in bytes (default 50MB). | | `MAILU_RELAYHOST` | *(empty)* | Upstream SMTP relay for outgoing mail, if any. | | `MAILU_RELAYNETS` | `172.16.0.0/12` | Networks granted relay permission; must include your Docker network. | | `MAILU_RECIPIENT_DELIMITER` | `+` | Character separating the local part from a custom tag (`user+tag@domain`). | | `MAILU_WEBMAIL` | `rainloop` | Which webmail client to run (`rainloop`, `roundcube`, or `none`). | | `MAILU_WEBDAV` | `radicale` | DAV server implementation (`radicale` or `none`). | | `MAILU_ADMIN` | `true` | Whether the admin web interface is exposed. | | `MAILU_AUTH_RATELIMIT` | `10/minute;1000/hour` | Login rate limit per source IP. | | `MAILU_RECAPTCHA_PUBLIC_KEY` | *(placeholder)* | reCAPTCHA public key, required for the signup form. | | `MAILU_RECAPTCHA_PRIVATE_KEY` | *(placeholder)* | reCAPTCHA private key, required for the signup form. | ## Set up a domain You'll need a registered domain and a [reCAPTCHA key pair](https://www.google.com/recaptcha/admin) for the signup email flow. In your `.env`: ```env MAILU_RECAPTCHA_PUBLIC_KEY= MAILU_RECAPTCHA_PRIVATE_KEY= MAILU_DOMAIN=laradock.io MAILU_HOSTNAMES=mail.laradock.io ``` Then [start the stack](#start-mailu) and open `http://YOUR_DOMAIN` (or `https://` with a proper `MAILU_TLS_FLAVOR`). ## Ports and real mail protocols Unlike the other mail services, Mailu's `mailu-front` container publishes real mail protocol ports directly, hardcoded in `mailu/compose.yml` rather than driven by env vars: `110` (POP3), `143` (IMAP), `993` (IMAPS), `995` (POP3S), `25` (SMTP), `465` (SMTPS), `587` (submission). Only the web ports (`MAILU_HTTP_PORT`, `MAILU_HTTPS_PORT`) are configurable via `.env`. This also means you can only run **one** Mailu stack per host at a time, since a second project can't rebind those same protocol ports. ## Initial admin login On first boot, the `mailu` container automatically provisions an admin account from `MAILU_INIT_ADMIN_USERNAME` and `MAILU_INIT_ADMIN_PASSWORD` (`laradock` / `laradock` by default), it's not something you need to unlock or dig out of a log file. - **Admin panel**: `http://:` (`http://localhost:6080/admin` with defaults). Log in with `MAILU_INIT_ADMIN_USERNAME@MAILU_DOMAIN` and `MAILU_INIT_ADMIN_PASSWORD`. - **Webmail**: `http://:` (`http://localhost:6080/webmail` with defaults), same credentials for any mailbox you create. Change `MAILU_INIT_ADMIN_PASSWORD` and `MAILU_SECRET_KEY` in your `.env` before using this for anything beyond local testing, both ship with placeholder values. ## Manage users and domains from the CLI The admin panel's signup form needs a working reCAPTCHA key pair. If you haven't set one up yet, create domains and mailboxes directly through `manage.py` inside the admin container instead: ```bash ./laradock enter mailu-admin ``` ```bash docker compose exec mailu-admin bash ``` Then, inside the container: ```bash python manage.py domain laradock.io python manage.py user newuser laradock.io somepassword ``` The same `manage.py admin ` form is what Laradock itself runs on first boot to create `MAILU_INIT_ADMIN_USERNAME` (see the `mailu` service's `command` in `mailu/compose.yml`), use it to promote any mailbox to admin. ## Backup and restore Everything Mailu owns (mailboxes, DKIM keys, webmail state, TLS certs, spam filter data, DAV data) lives under `DATA_PATH_HOST/mailu/`, there's no separate export tool like a database dump, it's just files on disk. Stop the stack first so nothing is mid-write: ```bash ./laradock stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` ```bash docker compose stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ``` Then archive the data folder: ```bash tar -czf mailu-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" mailu ``` To restore, stop the stack, delete or move aside the existing `DATA_PATH_HOST/mailu/` folder, extract the archive back into `DATA_PATH_HOST`, then [start Mailu](#start-mailu) again. ## Start completely fresh (wipe all data) To throw away every mailbox, domain, and cert and start Mailu from a clean, empty state (⚠️ this **permanently deletes** all mail data, back up first if you need anything): ```bash ./laradock stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail ./laradock remove mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mailu" ./laradock start mailu ``` ```bash docker compose stop mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail docker compose rm -sf mailu mailu-front mailu-imap mailu-smtp mailu-antispam mailu-antivirus mailu-webdav mailu-admin mailu-webmail mailu-fetchmail rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/mailu" docker compose up -d mailu ``` Deleting the folder and starting again re-provisions the admin account from `MAILU_INIT_ADMIN_USERNAME`/`MAILU_INIT_ADMIN_PASSWORD`, exactly like a brand-new install. ## Common issues - **Signup form doesn't work.** You still have placeholder reCAPTCHA keys (`MAILU_RECAPTCHA_PUBLIC_KEY`/`MAILU_RECAPTCHA_PRIVATE_KEY`). Generate a real pair and rebuild, or [create mailboxes from the CLI](#manage-users-and-domains-from-the-cli) instead. - **Mail rejected or not relayed.** Check `MAILU_RELAYNETS` includes your Docker network range, and that `MAILU_RELAYHOST` is set correctly if you're relaying through an upstream SMTP provider. - **Only the `mailu` container is running, the rest aren't.** `depends_on` only affects `up`, not `stop`. If you tore down the stack partially, bring everything back with `./laradock start mailu`. - **Data lost between restarts on multi-project setups.** Two Laradock projects on the same machine need unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST` values, otherwise they share the same `DATA_PATH_HOST/mailu/` data on disk. - **Second Laradock project won't start Mailu at all.** The real mail protocol ports (`25`, `110`, `143`, `465`, `587`, `993`, `995`) are hardcoded in `mailu/compose.yml`, not driven by `.env`, so only one Mailu stack can run per host regardless of `DATA_PATH_HOST`/`COMPOSE_PROJECT_NAME`. - **Just testing outgoing mail in dev, not building a real mail server?** Mailu is overkill for that, use a lightweight catcher instead. --- Just need to catch dev email, not run a real mail server? See **[Mailpit](https://laradock.io/docs/services/mailpit)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Grafana Source: https://laradock.io/docs/services/grafana ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Grafana? [Grafana](https://grafana.com) is the standard open-source dashboarding and visualization tool for metrics, most commonly paired with a time-series data source like Prometheus or InfluxDB. Laradock builds it as its own container so you can chart data from the other monitoring services without installing anything on your host. ## Start Grafana ```bash ./laradock start grafana ``` ```bash docker compose up -d grafana ``` Grafana is only useful once it has a data source to query, typically start it alongside `prometheus` or `influxdb`, for example `./laradock start grafana prometheus`. ## Stop Grafana Stopping just pauses the container; **your dashboards and data source config are safe** (kept under `DATA_PATH_HOST/grafana`): ```bash ./laradock stop grafana ``` ```bash docker compose stop grafana ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove grafana ``` ```bash docker compose rm -sf grafana ``` ## Configuration All settings live in `grafana/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `GRAFANA_PORT` | `3000` | Host-side port Grafana is published on (container port `3000`). | `grafana/Dockerfile` builds from `grafana/grafana:latest`, there's no version env var, see [Pin a specific version](#pin-a-specific-version) below if you need a fixed release instead of always tracking latest. ## Log in Open [http://localhost:3000](http://localhost:3000). Default credentials are user `admin`, password `admin`, Grafana will prompt you to change the password on first login. ## Add a data source From the web UI, go to **Connections β†’ Data sources β†’ Add data source** and point it at another Laradock container by name, for example `http://prometheus:9090` for Prometheus or `http://influxdb:8086` for InfluxDB (both reachable over the internal `backend` network). ## Reset the admin password If you changed the admin password after first login and forgot it, reset it from inside the container without losing any dashboards: ```bash ./laradock enter grafana ``` ```bash docker compose exec grafana bash ``` Then, inside the container: ```bash grafana-cli admin reset-admin-password newpassword ``` ## Backup and restore Grafana keeps everything, dashboards, data source configs, users, in a single SQLite database plus assets under `DATA_PATH_HOST/grafana`. Back it up as a plain file copy while the container is stopped, so the SQLite file isn't mid-write: ```bash ./laradock stop grafana ``` ```bash docker compose stop grafana ``` ```bash tar -czf grafana-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/grafana" . ``` Restart it once the copy finishes with `./laradock start grafana`. To restore, stop Grafana, clear the folder, extract the backup into it, then start again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/grafana"/* tar -xzf grafana-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/grafana" ``` For a single dashboard instead of the whole instance, use the web UI's **Share β†’ Export β†’ Save to file** on that dashboard to get a portable JSON file, no container access needed. ## Start completely fresh (wipe all data) To throw away every dashboard, data source, and user and start Grafana from a clean, empty state (⚠️ this **permanently deletes** everything, back up first if you need any of it): ```bash ./laradock stop grafana ./laradock remove grafana rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/grafana" ./laradock start grafana ``` ```bash docker compose stop grafana docker compose rm -sf grafana rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/grafana" docker compose up -d grafana ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default). Deleting the folder and starting again re-runs first-boot setup: the `admin`/`admin` login, an empty dashboard list, and no data sources, exactly like a brand-new install. ## Pin a specific version `grafana/Dockerfile` builds from `grafana/grafana:latest`, so a plain rebuild always pulls whatever Grafana currently tags as latest. To pin a fixed version instead, edit the `FROM` line in `grafana/Dockerfile`: ```dockerfile FROM grafana/grafana:11.2.0 ``` Then apply the change: ```bash ./laradock rebuild grafana ``` ```bash docker compose build grafana ``` ## Common issues - **Can't log in.** Default credentials are `admin`/`admin`. If you already changed the password and forgot it, [reset it](#reset-the-admin-password) from inside the container instead of wiping `DATA_PATH_HOST/grafana` (that loses every dashboard too). - **Port already in use on your host.** Change `GRAFANA_PORT` in `.env` and restart: `./laradock restart grafana`. - **Data source connection fails.** Use the container name (`prometheus`, `influxdb`, etc.), not `localhost`, when configuring a data source URL, Grafana runs in its own container and can't reach your host's `localhost`. - **Dashboards disappear after a rebuild.** Dashboards and data source configs persist under `DATA_PATH_HOST/grafana`; if you changed `DATA_PATH_HOST` or ran on a fresh data folder, they won't carry over. --- Visualizing metrics from Prometheus? See **[Prometheus](https://laradock.io/docs/services/prometheus)**. Need a time-series store instead? See **[InfluxDB](https://laradock.io/docs/services/influxdb)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Graylog Source: https://laradock.io/docs/services/graylog ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Graylog? [Graylog](https://www.graylog.org) is an open-source log management platform: it centralizes, indexes, and lets you search logs from your application and infrastructure through a web UI. It stores metadata in MongoDB and log data in Elasticsearch. Laradock builds it as its own container, wired to Laradock's `mongo` and `elasticsearch` containers. ## Start Graylog ```bash ./laradock start graylog ``` ```bash docker compose up -d graylog ``` `graylog/compose.yml` lists `mongo` and `elasticsearch` as `depends_on`, so both start automatically alongside it. ## Stop Graylog Stopping just pauses the container; **its own working data is safe** (kept under `DATA_PATH_HOST/graylog`): ```bash ./laradock stop graylog ``` ```bash docker compose stop graylog ``` To delete the container entirely (the data on disk is still untouched): ```bash ./laradock remove graylog ``` ```bash docker compose rm -sf graylog ``` ## Configuration All settings live in `graylog/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `GRAYLOG_PASSWORD` | `somesupersecretpassword` | Plain-text reminder of the admin password; not read directly, see below. | | `GRAYLOG_SHA256_PASSWORD` | `b1cb6e31e172577918c9e7806c572b5ed8477d3f57aa737bee4b5b1db3696f09` | SHA-256 hash of the admin password, this is what Graylog actually authenticates against. | | `GRAYLOG_PORT` | `9000` | Host-side port for the web UI and REST API. | | `GRAYLOG_SYSLOG_TCP_PORT` | `514` | Host-side port for Syslog over TCP. | | `GRAYLOG_SYSLOG_UDP_PORT` | `514` | Host-side port for Syslog over UDP. | | `GRAYLOG_GELF_TCP_PORT` | `12201` | Host-side port for GELF over TCP. | | `GRAYLOG_GELF_UDP_PORT` | `12201` | Host-side port for GELF over UDP. | ## Set a real password The password must be at least 16 characters. Set both the plain-text reminder and its hash in your `.env`: ```env GRAYLOG_PASSWORD=somesupersecretpassword GRAYLOG_SHA256_PASSWORD=b1cb6e31e172577918c9e7806c572b5ed8477d3f57aa737bee4b5b1db3696f09 ``` Generate the hash with: `echo -n somesupersecretpassword | sha256sum`. ## Log in and create an input Open [http://localhost:9000](http://localhost:9000) and sign in as `admin` with your password. Go to **System β†’ Inputs** and launch a new input (GELF or Syslog, TCP or UDP) to start receiving logs on the corresponding port above. ## Send logs from your app Once an input is running, point your app's logging driver at it instead of (or alongside) local log files: - **GELF** (structured, recommended): send to `127.0.0.1` on `GRAYLOG_GELF_TCP_PORT`/`GRAYLOG_GELF_UDP_PORT` (`12201` by default). Laravel's Monolog stack supports a GELF handler; most other frameworks have an equivalent GELF logging library. - **Syslog** (plain-text, for infra/system logs): send to `127.0.0.1` on `GRAYLOG_SYSLOG_TCP_PORT`/`GRAYLOG_SYSLOG_UDP_PORT` (`514` by default). If your app runs in another Laradock container (not on your host), it can't reach Graylog by container name unless it's on the same `backend` network; the published host ports above work from anywhere, including from inside other containers via `host.docker.internal`. ## Where your data actually lives The volume mounted into the container (`DATA_PATH_HOST/graylog`) only holds Graylog's **own** working state: its node ID and local message journal. The two things you probably care about for backups live elsewhere: - **Log messages** are indexed and stored by **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)**, not by Graylog itself. - **Everything you configure in the UI** (streams, dashboards, alerts, inputs, users) is metadata stored in **[MongoDB](https://laradock.io/docs/services/mongo)**. To actually back up your Graylog setup, back up the `mongo` and `elasticsearch` containers' data, not `graylog/`'s own folder. ## Start completely fresh (wipe all data) To throw away Graylog's own working state and start it from a clean slate (⚠️ this does **not** touch your indexed logs in Elasticsearch or your dashboards/streams in MongoDB, wipe those separately if you want a fully clean logging stack): ```bash ./laradock stop graylog ./laradock remove graylog rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/graylog" ./laradock start graylog ``` ```bash docker compose stop graylog docker compose rm -sf graylog rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/graylog" docker compose up -d graylog ``` ## Common issues - **Login fails even with the right password.** Graylog authenticates against `GRAYLOG_SHA256_PASSWORD`, not `GRAYLOG_PASSWORD`. If you changed the plain-text value but forgot to regenerate and update the hash, login will fail. - **Graylog won't start or logs errors about Elasticsearch/MongoDB.** Confirm both dependencies are actually up: `docker compose ps mongo elasticsearch`. - **Port `514` conflicts on your host.** Port 514 is a privileged port often reserved by system syslog daemons. Change `GRAYLOG_SYSLOG_TCP_PORT`/`GRAYLOG_SYSLOG_UDP_PORT` in `.env` and restart with `./laradock restart graylog`. - **Logs aren't showing up.** You need to create an input first under **System β†’ Inputs**, Graylog doesn't listen on any protocol by default until one is configured. --- Want infrastructure/host metrics instead of application logs? See **[NetData](https://laradock.io/docs/services/netdata)** or **[Prometheus](https://laradock.io/docs/services/prometheus)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # InfluxDB Source: https://laradock.io/docs/services/influxdb ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is InfluxDB? [InfluxDB](https://www.influxdata.com) is an open-source time-series database purpose-built for high-volume metrics, events, and IoT/analytics data. It's commonly paired with Grafana for dashboards. Laradock builds it (InfluxDB 2.x) as its own container from the official image. ## Start InfluxDB ```bash ./laradock start influxdb ``` ```bash docker compose up -d influxdb ``` Your organization, bucket, and admin user are created on first boot and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start influxdb workspace`. ## Stop InfluxDB Stopping just pauses the container; **your data is safe** (kept in the `influxdb` volume): ```bash ./laradock stop influxdb ``` ```bash docker compose stop influxdb ``` To delete the container entirely (the data in the `influxdb` volume is still untouched): ```bash ./laradock remove influxdb ``` ```bash docker compose rm -sf influxdb ``` ## Configuration All settings live in `influxdb/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `INFLUXDB_VERSION` | `2.7` | Image version built via `influxdb/Dockerfile`. | | `INFLUXDB_HOST_PORT` | `8086` | Host-side port InfluxDB is published on (container port `8086`). | | `INFLUXDB_INIT_USERNAME` | `laradock` | Admin username created on first boot. | | `INFLUXDB_INIT_PASSWORD` | `secretpassword` | Password for that admin user. | | `INFLUXDB_INIT_ORG` | `laradock` | Organization created on first boot. | | `INFLUXDB_INIT_BUCKET` | `default` | Bucket (database) created on first boot. | These map directly to InfluxDB's own `DOCKER_INFLUXDB_INIT_*` environment variables (set in `influxdb/compose.yml`), with `DOCKER_INFLUXDB_INIT_MODE=setup` triggering the automatic first-run setup. Data itself persists in the `influxdb` **named Docker volume**, mounted at `/var/lib/influxdb2` inside the container, not a `DATA_PATH_HOST` folder. ## Connect Open the UI and API at [http://localhost:8086](http://localhost:8086); check readiness with `curl http://localhost:8086/health`. Log in with `INFLUXDB_INIT_USERNAME`/`INFLUXDB_INIT_PASSWORD`, org `INFLUXDB_INIT_ORG`, bucket `INFLUXDB_INIT_BUCKET`. From another container, use `http://influxdb:8086`. The UI login is username/password, but the write and query **APIs** (and any client library, including Grafana's InfluxDB data source) need a token instead, see [Get an API token](#get-an-api-token) below. ## Get an API token `influxdb/compose.yml` doesn't pin `DOCKER_INFLUXDB_INIT_ADMIN_TOKEN`, so InfluxDB generates a random all-access token during first-run setup rather than a predictable one. The official image also writes a CLI config pointing at that token, so the `influx` CLI works inside the container without any extra flags. Open a terminal inside the container and list existing tokens: ```bash ./laradock enter influxdb ``` ```bash docker compose exec influxdb bash ``` Then, inside the container: ```bash influx auth list ``` Or from the UI: log in at [http://localhost:8086](http://localhost:8086), then **Load Data > API Tokens** to view or copy one. Use the token in an `Authorization: Token ` header on API requests, or paste it into Grafana's InfluxDB data source config. To create a new, separate token instead of reusing the auto-generated one: ```bash influx auth create --org laradock --all-access ``` ## Buckets and retention A bucket is InfluxDB 2.x's unit of storage, roughly a database and a retention period combined. `INFLUXDB_INIT_BUCKET` only creates one bucket on first boot; day-to-day you'll likely want more, each with its own retention. List existing buckets (run after `./laradock enter influxdb`, same as above): ```bash influx bucket list --org laradock ``` Create a new bucket with, for example, 30 days of retention: ```bash influx bucket create --name metrics_30d --org laradock --retention 30d ``` ## Backup and restore **Back up** all organizations and buckets to a folder inside the container, then copy that folder to your host: ```bash ./laradock exec influxdb influx backup /tmp/influxdb-backup ``` ```bash docker compose exec influxdb influx backup /tmp/influxdb-backup ``` ```bash docker cp "$(docker compose ps -q influxdb)":/tmp/influxdb-backup ./influxdb-backup ``` **Restore** by copying a backup folder back in, then restoring from it: ```bash docker cp ./influxdb-backup "$(docker compose ps -q influxdb)":/tmp/influxdb-backup ``` ```bash ./laradock exec influxdb influx restore /tmp/influxdb-backup ``` ```bash docker compose exec influxdb influx restore /tmp/influxdb-backup ``` Restore flags and behavior have changed across InfluxDB releases, check the [InfluxDB backup/restore docs](https://docs.influxdata.com/influxdb/v2/backup-restore/) for options specific to your `INFLUXDB_VERSION`. Keep the `influxdb-backup` folder itself somewhere safe, it's the actual backup. ## Start completely fresh (wipe all data) To throw away every organization, bucket, and data point, and start InfluxDB from a clean, empty state (⚠️ this **permanently deletes** everything in the `influxdb` volume, back up first if you need anything): ```bash ./laradock stop influxdb ./laradock remove influxdb docker volume rm "${COMPOSE_PROJECT_NAME}_influxdb" ./laradock start influxdb ``` ```bash docker compose stop influxdb docker compose rm -sf influxdb docker volume rm "${COMPOSE_PROJECT_NAME}_influxdb" docker compose up -d influxdb ``` Unlike bind-mounted services, InfluxDB's storage lives in a **named Docker volume**, not a folder under `DATA_PATH_HOST`, so wiping it means removing the volume itself. If you're unsure of the exact volume name on your machine (it's prefixed with your `COMPOSE_PROJECT_NAME`), list it first with `docker volume ls | grep influxdb`. Deleting it and starting again re-runs first-boot setup: `INFLUXDB_INIT_USERNAME`, `INFLUXDB_INIT_PASSWORD`, `INFLUXDB_INIT_ORG`, and `INFLUXDB_INIT_BUCKET` all apply fresh, and a new admin token is generated, exactly like a brand-new install. ## Talk to this database from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this InfluxDB by container name out of the box. Easiest fix: the API port is already published (`INFLUXDB_HOST_PORT`), so point the other project (or a shared Grafana) at your **host machine's** address instead of `influxdb`, for example `http://host.docker.internal:8086` (Docker Desktop). Make sure the two projects use different `INFLUXDB_HOST_PORT` values if they're both running at once. ## Common issues - **Port already in use on your host.** Change `INFLUXDB_HOST_PORT` in `.env` and restart: `./laradock restart influxdb`. - **`INFLUXDB_INIT_*` changes don't take effect.** These only apply during the automatic first-run setup. If InfluxDB already initialized its volume, changing them afterward has no effect, you'd need to create a new user/org/bucket manually or [start completely fresh](#start-completely-fresh-wipe-all-data). - **Default credentials in a shared environment.** `secretpassword` is a placeholder meant for local dev only, override `INFLUXDB_INIT_PASSWORD` in `.env` before exposing this beyond your machine. - **API requests return `401 Unauthorized`.** The UI login (username/password) doesn't work for the write/query API, you need a token, see [Get an API token](#get-an-api-token). - **App can't connect but the container is running.** Confirm your app or Grafana data source uses `influxdb` as the host, not `localhost`, that only works from your host machine. --- Want to chart this data with dashboards? See **[Grafana](https://laradock.io/docs/services/grafana)**. Want PromQL-based metrics instead? See **[Prometheus](https://laradock.io/docs/services/prometheus)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Logstash Source: https://laradock.io/docs/services/logstash ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Logstash? [Logstash](https://www.elastic.co/logstash) is the "L" in the ELK stack: a server-side data processing pipeline that ingests logs and events from multiple sources, transforms them, and ships them to a destination like Elasticsearch. Laradock builds it version-matched to **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)** and **[Kibana](https://laradock.io/docs/services/kibana)** via the shared `ELK_VERSION` variable in the root `.env`. ## Start Logstash ```bash ./laradock start logstash ``` ```bash docker compose up -d logstash ``` `logstash/compose.yml` lists `elasticsearch` as a dependency, so it starts automatically alongside Logstash. Logstash has nowhere to ship data without it. ## Stop Logstash ```bash ./laradock stop logstash ``` ```bash docker compose stop logstash ``` To remove the container: ```bash ./laradock remove logstash ``` ```bash docker compose rm -sf logstash ``` ## Configuration Logstash has no `logstash/defaults.env`. It's built from `logstash/Dockerfile` using the shared `ELK_VERSION` variable in the root `.env` (the same version used for `elasticsearch` and `kibana`). The port and JVM heap size are fixed directly in `logstash/compose.yml`, not exposed as `.env` variables: | Setting | Value | Where it's set | |---|---|---| | Port | `5001:5001` | `logstash/compose.yml` | | `LS_JAVA_OPTS` | `-Xmx1g -Xms1g` | `logstash/compose.yml` | ## Configure the pipeline `logstash/compose.yml` mounts `logstash/config/logstash.yml` (server config: binds to `0.0.0.0`, disables X-Pack monitoring, auto-reloads config) and `logstash/pipeline/` (your `.conf` pipeline files) into the container. Drop your input/filter/output pipeline files into `logstash/pipeline/`, config reload is automatic (`config.reload.automatic: true`), so changes apply without a restart. The image also has the `logstash-input-beats` plugin pre-installed and a MySQL JDBC driver (`mysql-connector-java-5.1.47.jar`) baked in via `logstash/Dockerfile`, useful if you're piping data from Filebeat/Metricbeat or querying MySQL directly from a pipeline. ### Example pipeline `logstash/pipeline/` ships empty (just a `.gitkeep`), so nothing is processed until you add a `.conf` file. A minimal one that takes Beats input and ships straight to Elasticsearch: ```conf input { beats { port => 5044 } } output { elasticsearch { hosts => ["elasticsearch:9200"] index => "logs-%{+YYYY.MM.dd}" } } ``` Save it as `logstash/pipeline/logstash.conf` and Logstash picks it up automatically, no restart needed. Use the container name `elasticsearch` as the output host, not `localhost`, Logstash and Elasticsearch talk to each other over the `frontend`/`backend` networks. ### Test a pipeline before it goes live Config reload is automatic, but a syntax error in a live pipeline file just makes Logstash fail to reload silently. Check a pipeline file's syntax before relying on it: ```bash ./laradock exec -T logstash bin/logstash --config.test_and_exit ``` ```bash docker compose exec -T logstash bin/logstash --config.test_and_exit ``` This validates everything under `path.config` (`/usr/share/logstash/pipeline`, set in `logstash/config/logstash.yml`) and exits without starting the pipeline, so it's safe to run against a container that's already processing data. ### Check installed plugins Confirm the pre-installed `logstash-input-beats` plugin (or anything else you've added) is actually there: ```bash ./laradock exec -T logstash bin/logstash-plugin list ``` ```bash docker compose exec -T logstash bin/logstash-plugin list ``` ## Common issues - **No pipeline is running.** The `logstash/pipeline/` folder ships empty (just a `.gitkeep`). Logstash needs at least one `.conf` file with an `input`/`output` block before it processes anything, see [Example pipeline](#example-pipeline) above. - **Can't reach Elasticsearch.** Use the container name `elasticsearch` as the output host in your pipeline config, not `localhost`, Logstash runs in its own container on the `frontend`/`backend` networks. - **Version mismatch with Elasticsearch/Kibana.** All three read `ELK_VERSION` from the root `.env`. If you changed it for one manually, rebuild all three: `./laradock rebuild logstash elasticsearch kibana`. - **Out of memory under load.** Heap is fixed at `-Xmx1g -Xms1g` via `LS_JAVA_OPTS` in `logstash/compose.yml`. Raise it there if you're processing large volumes locally. - **Port `5001` already in use on your host.** This port is hardcoded in `logstash/compose.yml`, there's no env var to override it; free the port or edit the compose file directly. --- Need the search/storage backend? See **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)**. Need to visualize the ingested data? See **[Kibana](https://laradock.io/docs/services/kibana)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # NetData Source: https://laradock.io/docs/services/netdata ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is NetData? [NetData](https://www.netdata.cloud) is a real-time performance monitoring tool that needs essentially no configuration: point it at a host and it starts charting CPU, memory, disk I/O, network, and per-process metrics immediately in a web dashboard. Laradock runs it from the official `netdata/netdata` image with access to the host's `/proc`, `/sys`, and the Docker socket, so it can monitor the machine Docker itself is running on, not just the container. ## Start NetData ```bash ./laradock start netdata ``` ```bash docker compose up -d netdata ``` ## Stop NetData ```bash ./laradock stop netdata ``` ```bash docker compose stop netdata ``` To remove the container: ```bash ./laradock remove netdata ``` ```bash docker compose rm -sf netdata ``` ## Configuration All settings live in `netdata/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `NETDATA_PORT` | `19999` | Host-side port the NetData dashboard is published on (container port `19999`). | ## View the dashboard Open [http://localhost:19999](http://localhost:19999). Charts update live, no login or setup required, NetData ships wide open by default (no auth on the dashboard), so don't expose `NETDATA_PORT` beyond your local machine or a trusted network. ## What it can see `netdata/compose.yml` mounts the host's `/proc` and `/sys` read-only and adds the `SYS_PTRACE` capability, so NetData reports on the Docker host itself (all processes, all containers), not just its own container. It also mounts `/var/run/docker.sock` read-only to report per-container Docker stats. ## Data retention (metrics are not persisted by default) `netdata/compose.yml` doesn't mount a volume for NetData's own storage (`/var/cache/netdata` for its metrics database, `/etc/netdata` for config), so everything NetData collects and any dashboard settings live only inside the running container's writable layer: - `./laradock stop netdata` / `docker compose stop netdata` keeps the container intact, history is safe across a stop/start. - `./laradock remove netdata` / `docker compose rm -sf netdata` deletes the container, and with it **all collected history**. The next `start` boots a completely empty NetData with no charts before it, exactly as if freshly installed, there's nothing to explicitly "wipe" beyond removing the container. If you want metrics and config to survive a `remove`/rebuild, add your own bind mounts to `netdata/compose.yml` before starting it for the first time: ```yaml volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /var/run/docker.sock:/var/run/docker.sock:ro - netdata-lib:/var/lib/netdata - netdata-cache:/var/cache/netdata - netdata-config:/etc/netdata ``` (declare `netdata-lib`, `netdata-cache`, and `netdata-config` under a top-level `volumes:` key). This isn't Laradock's default, since NetData is normally used for live/short-term monitoring rather than long-term retention, add it only if you specifically need history to outlive a container recreate. ## Check status via the API NetData exposes its own data over a REST API, useful for scripting or a quick health check without opening the dashboard: ```bash curl http://localhost:19999/api/v1/info ``` ## Common issues - **Port already in use on your host.** Change `NETDATA_PORT` in `.env` and restart: `./laradock restart netdata`. - **Metrics look like they're for the whole machine, not just Laradock.** That's expected, NetData mounts the host's `/proc` and `/sys`, so it reports on everything running on the Docker host, not a sandboxed view of just this project. - **Missing per-process detail.** Some deeper process-level metrics need the `SYS_PTRACE` capability, already granted in `netdata/compose.yml`; if you're running a hardened Docker setup that strips capabilities globally, NetData's visibility will be reduced. - **All my charts disappeared.** Expected if you ran `./laradock remove netdata` (or rebuilt it): metrics aren't persisted by default, see [Data retention](#data-retention-metrics-are-not-persisted-by-default) above. --- Want application logs instead of host metrics? See **[Graylog](https://laradock.io/docs/services/graylog)**. Want metrics with PromQL and dashboards? See **[Prometheus](https://laradock.io/docs/services/prometheus)** and **[Grafana](https://laradock.io/docs/services/grafana)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Prometheus Source: https://laradock.io/docs/services/prometheus ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Prometheus? [Prometheus](https://prometheus.io) is the standard open-source metrics and monitoring system: it scrapes metrics from configured targets on an interval, stores them as time series, and lets you query them with PromQL. It's the usual data source behind Laradock's Grafana. Laradock runs it from the official `prom/prometheus` image. ## Start Prometheus ```bash ./laradock start prometheus ``` ```bash docker compose up -d prometheus ``` Name any other services alongside it to start them together, for example `./laradock start prometheus grafana`. ## Stop Prometheus Stopping just pauses the container; **your stored metrics are safe** (kept in the `prometheus` volume): ```bash ./laradock stop prometheus ``` ```bash docker compose stop prometheus ``` To delete the container entirely (the metrics in the `prometheus` volume are still untouched): ```bash ./laradock remove prometheus ``` ```bash docker compose rm -sf prometheus ``` ## Configuration All settings live in `prometheus/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `PROMETHEUS_VERSION` | `v3.13.0` | Image tag from [Prometheus's Docker Hub](https://hub.docker.com/r/prom/prometheus). | | `PROMETHEUS_HOST_PORT` | `9091` | Host-side port Prometheus is published on (container port `9090`). | ## Check it's running Open the web UI at [http://localhost:9091](http://localhost:9091), or check the health endpoint: `curl http://localhost:9091/-/healthy`. There's no login by default, Prometheus's web UI and API are open to anyone who can reach the port. Don't publish `PROMETHEUS_HOST_PORT` beyond your local machine without putting something (a reverse proxy with auth, a firewall rule) in front of it. ## Add scrape targets Edit `prometheus/prometheus.yml` (mounted read-only into the container) to add jobs and targets, then apply the change: ```bash ./laradock restart prometheus ``` ```bash docker compose restart prometheus ``` Target other Laradock containers by their service name, not `localhost`, for example `php-fpm:9253` for a php-fpm exporter or `mysqld-exporter:9104` for MySQL. Prometheus's own container joins the `frontend` and `backend` networks, so it can reach anything else on either. ## Query metrics with PromQL The web UI's **Graph** tab (`http://localhost:9091/graph`) lets you run PromQL queries interactively. A few to get started, all valid against the built-in self-scrape: ```promql up ``` ```promql rate(prometheus_http_requests_total[5m]) ``` `up` returns `1`/`0` per scrape target and is the fastest way to check whether a target is being reached at all; start troubleshooting any "missing metrics" problem there before writing a more specific query. ## Data retention By default Prometheus keeps **15 days** of data in the `prometheus` volume, then drops the oldest samples as new ones come in. To change that, add a `command:` override in `prometheus/compose.yml` with a longer or shorter `--storage.tsdb.retention.time`: ```yaml services: prometheus: command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus - --storage.tsdb.retention.time=30d ``` Apply it: ```bash ./laradock restart prometheus ``` ```bash docker compose restart prometheus ``` Longer retention means more disk usage in the `prometheus` volume, there's no automatic size cap, only the time-based one. ## Start completely fresh (wipe stored metrics) Metrics live in the named `prometheus` Docker volume, not a bind mount under `DATA_PATH_HOST`, so wiping it works a little differently than for a service with a data folder on disk. To throw away all stored history and start clean (⚠️ this **permanently deletes** every metric this container has collected): ```bash ./laradock stop prometheus ./laradock remove prometheus docker volume rm "${COMPOSE_PROJECT_NAME:-laradock}_prometheus" ./laradock start prometheus ``` ```bash docker compose stop prometheus docker compose rm -sf prometheus docker volume rm "${COMPOSE_PROJECT_NAME:-laradock}_prometheus" docker compose up -d prometheus ``` `COMPOSE_PROJECT_NAME` (`laradock` by default) prefixes every volume Compose creates, run `docker volume ls | grep prometheus` first if you're not sure of the exact name on your machine, especially if you run multiple Laradock projects. ## Scrape a target in another Laradock project Each Laradock project is its own isolated Docker network by default, so this Prometheus can't reach another project's containers by service name. Point the scrape target at the other project's **host-published port** instead: in `prometheus/prometheus.yml`, use `host.docker.internal:` (Docker Desktop) with whatever host port that service publishes (its own `*_HOST_PORT`/`*_PORT` variable), then [restart](#add-scrape-targets). ## Common issues - **Port already in use on your host.** Change `PROMETHEUS_HOST_PORT` in `.env` and restart: `./laradock restart prometheus`. - **New scrape targets aren't picked up.** Prometheus reads `prometheus.yml` at startup; after editing it you need to `./laradock restart prometheus`, not just save the file. - **Data disappears after `docker compose down -v`.** Metrics live in the named `prometheus` volume, not a bind mount. Removing volumes (`docker compose down -v`) deletes that history along with everything else. - **Can't reach a scrape target from inside the container.** Use container names (`php-fpm`, `nginx`, etc.) as targets, not `localhost`, Prometheus runs in its own container on the `frontend`/`backend` networks. - **Target shows `up == 0`.** The target itself either isn't exposing a `/metrics` endpoint, isn't running, or isn't reachable on the network/port you configured, check with `curl` from inside the workspace container before assuming Prometheus is misconfigured. --- Want to chart this data with dashboards? See **[Grafana](https://laradock.io/docs/services/grafana)**. Need a general-purpose time-series store instead? See **[InfluxDB](https://laradock.io/docs/services/influxdb)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Dejavu Source: https://laradock.io/docs/services/dejavu ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Dejavu? [Dejavu](https://github.com/appbaseio/dejavu) is a lightweight, open-source web UI for browsing and querying Elasticsearch indices, import/export data, inspect mappings, and build queries visually, without Kibana's full dashboarding weight. Laradock builds it from the `appbaseio/dejavu` image. ## Start Dejavu `dejavu/compose.yml` lists `elasticsearch` as a dependency, so it starts automatically alongside Dejavu, there's nothing to browse without it: ```bash ./laradock start dejavu ``` ```bash docker compose up -d dejavu ``` ## Stop Dejavu Dejavu itself keeps no data of its own (it's just a browser-side UI, your actual data lives in Elasticsearch), so there's nothing to back up here: ```bash ./laradock stop dejavu ``` ```bash docker compose stop dejavu ``` To delete the container entirely: ```bash ./laradock remove dejavu ``` ```bash docker compose rm -sf dejavu ``` ## Configuration The only Laradock-specific setting lives in `dejavu/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `DEJAVU_HTTP_PORT` | `1358` | Host-side port Dejavu is published on (container port `1358`). | The Dejavu image itself isn't version-pinned, `dejavu/Dockerfile` builds from `appbaseio/dejavu` (latest). ## Connect Open [http://localhost:1358](http://localhost:1358) in your browser. When prompted for a connection, point it at your Elasticsearch endpoint: use `http://localhost:9200` if you're browsing from the same machine (Dejavu runs client-side in your browser and talks to Elasticsearch directly over HTTP, not through the Dejavu container). Laradock's default `elasticsearch/compose.yml` sets `xpack.security.enabled=false`, so there's no login to enter, just the URL. ## Enable CORS on Elasticsearch Dejavu's connection screen is the most common first-run blocker: browsers block cross-origin requests from `localhost:1358` to `localhost:9200` unless Elasticsearch explicitly allows it, and Laradock's default config doesn't. Add these lines to the `environment:` block in `elasticsearch/compose.yml`: ```yaml - http.cors.enabled=true - http.cors.allow-origin=http://localhost:1358 ``` Then rebuild and restart Elasticsearch to pick up the change: ```bash ./laradock restart elasticsearch ``` ```bash docker compose restart elasticsearch ``` If you changed `DEJAVU_HTTP_PORT`, update `http.cors.allow-origin` to match. ## Update to the latest Dejavu version The image is built fresh from `appbaseio/dejavu` with no version pin, so Laradock always uses whatever tag Docker last pulled locally. To force a newer image and rebuild: ```bash ./laradock rebuild dejavu --pull ``` ```bash docker compose build --pull dejavu ``` Then restart it: `./laradock restart dejavu`. ## Browse an Elasticsearch cluster from another Laradock project Dejavu isn't tied to the `elasticsearch` container it starts with, its connection screen accepts any reachable URL. To browse a different project's cluster (or a remote one), publish that cluster's HTTP port and enter its host address instead of `localhost:9200`, for example `http://host.docker.internal:9200` (Docker Desktop) if you're pointing at another Laradock project's Elasticsearch on the same machine. Make sure that project's `ELASTICSEARCH_HOST_HTTP_PORT` is unique if both are running at once, and that its Elasticsearch also has CORS enabled for Dejavu's origin (see [Enable CORS on Elasticsearch](#enable-cors-on-elasticsearch) above). ## Common issues - **"Could not connect" when adding a connection.** Elasticsearch needs CORS enabled to accept cross-origin requests from Dejavu's browser UI, see [Enable CORS on Elasticsearch](#enable-cors-on-elasticsearch) above. - **Blank page or connection refused.** Confirm `elasticsearch` is actually up first: `./laradock info` and `./laradock logs elasticsearch`. - **Port already in use on your host.** Change `DEJAVU_HTTP_PORT` in `.env` and restart: `./laradock restart dejavu`. --- Need full dashboards and visualizations instead? See **[Kibana](https://laradock.io/docs/services/kibana)**. Need the underlying engine? See **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Elasticsearch Source: https://laradock.io/docs/services/elasticsearch ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Elasticsearch? [Elasticsearch](https://www.elastic.co/elasticsearch) is a distributed search and analytics engine built on Apache Lucene. It's the "ES" in the ELK stack and a common backend for full-text search, log analytics, and Laravel Scout's Elasticsearch driver. Laradock builds it as its own container from the official image. ## Start Elasticsearch ```bash ./laradock start elasticsearch ``` ```bash docker compose up -d elasticsearch ``` The `elasticsearch/compose.yml` lists `php-fpm` as a dependency, so `php-fpm` starts automatically alongside it. Your indices are created as you write to them and persist between restarts in a named Docker volume. ## Stop Elasticsearch Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop elasticsearch ``` ```bash docker compose stop elasticsearch ``` To delete the container entirely (the data volume is untouched): ```bash ./laradock remove elasticsearch ``` ```bash docker compose rm -sf elasticsearch ``` ## Configuration Laradock builds the image from `elasticsearch/Dockerfile` using the shared `ELK_VERSION` variable in the root `.env` (also used by `kibana`), plus these settings in `elasticsearch/defaults.env`: | Variable | Default | What it does | |---|---|---| | `ELASTICSEARCH_HOST_HTTP_PORT` | `9200` | Host-side port for the REST API (container port `9200`). | | `ELASTICSEARCH_HOST_TRANSPORT_PORT` | `9300` | Host-side port for the transport/cluster protocol (container port `9300`). | The container also runs single-node with security disabled by default (`xpack.security.enabled=false`), and JVM heap capped at `-Xms512m -Xmx512m` via `ES_JAVA_OPTS`, both set directly in `elasticsearch/compose.yml`. ## Connect Open [http://localhost:9200](http://localhost:9200) from your host, or `http://elasticsearch:9200` from another container. There's no authentication by default since the security plugin is disabled, unlike the hosted Elastic Cloud default of user `elastic` / a generated password. ## Check cluster and index health A quick sanity check that the node is up and see the overall cluster status (`green`/`yellow`/`red`): ```bash ./laradock exec -T elasticsearch curl -s "localhost:9200/_cluster/health?pretty" ``` ```bash docker compose exec -T elasticsearch curl -s "localhost:9200/_cluster/health?pretty" ``` `yellow` is normal and expected for Laradock's single-node setup (replica shards can never be assigned with only one node), it only becomes a real concern if you see `red`. To list every index with its doc count and size: ```bash ./laradock exec -T elasticsearch curl -s "localhost:9200/_cat/indices?v" ``` ```bash docker compose exec -T elasticsearch curl -s "localhost:9200/_cat/indices?v" ``` ## Install a plugin ```bash ./laradock exec elasticsearch /usr/share/elasticsearch/bin/plugin install ``` ```bash docker compose exec elasticsearch /usr/share/elasticsearch/bin/plugin install ``` Then apply it: ```bash ./laradock restart elasticsearch ``` ```bash docker compose restart elasticsearch ``` ## Backup and restore Elasticsearch doesn't export to a single file the way a SQL database does, it uses **snapshots** written to a repository directory that must first be registered with the cluster and mounted into the container. Add a shared folder for it in `elasticsearch/compose.yml` under `volumes`, for example `- ./elasticsearch/snapshots:/usr/share/elasticsearch/snapshots`, then register the repository: ```bash ./laradock exec -T elasticsearch curl -X PUT "localhost:9200/_snapshot/backup" -H "Content-Type: application/json" -d '{"type":"fs","settings":{"location":"/usr/share/elasticsearch/snapshots"}}' ``` ```bash docker compose exec -T elasticsearch curl -X PUT "localhost:9200/_snapshot/backup" -H "Content-Type: application/json" -d '{"type":"fs","settings":{"location":"/usr/share/elasticsearch/snapshots"}}' ``` **Take a snapshot** of every index: ```bash ./laradock exec -T elasticsearch curl -X PUT "localhost:9200/_snapshot/backup/snapshot_1?wait_for_completion=true" ``` ```bash docker compose exec -T elasticsearch curl -X PUT "localhost:9200/_snapshot/backup/snapshot_1?wait_for_completion=true" ``` **Restore** it later (into an empty cluster, or after closing the indices you're overwriting): ```bash ./laradock exec -T elasticsearch curl -X POST "localhost:9200/_snapshot/backup/snapshot_1/_restore?wait_for_completion=true" ``` ```bash docker compose exec -T elasticsearch curl -X POST "localhost:9200/_snapshot/backup/snapshot_1/_restore?wait_for_completion=true" ``` For most local dev workflows, a full re-index from your app's own source of truth (the database driving Laravel Scout, for example) is simpler than snapshot/restore, reach for snapshots when you specifically need to preserve indices that can't be cheaply rebuilt. ## Start completely fresh (wipe all data) Elasticsearch's data lives in a named Docker volume, not a `DATA_PATH_HOST` folder, so wiping it means removing that volume (⚠️ this **permanently deletes** every index, back up first if you need anything): ```bash ./laradock stop elasticsearch ./laradock remove elasticsearch docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_elasticsearch ./laradock start elasticsearch ``` ```bash docker compose stop elasticsearch docker compose rm -sf elasticsearch docker volume rm ${COMPOSE_PROJECT_NAME:-laradock}_elasticsearch docker compose up -d elasticsearch ``` `COMPOSE_PROJECT_NAME` is whatever you have set in `.env` (`laradock` by default); Docker prefixes named volumes with it, so the volume above is the actual one backing this container. Not sure of the exact name? List it first with `docker volume ls | grep elasticsearch`. ## Reindex or delete a single index To rebuild one index without touching the rest of the cluster, delete it and let your app's indexer (Laravel Scout's `scout:import`, for example) recreate it: ```bash ./laradock exec -T elasticsearch curl -X DELETE "localhost:9200/your_index_name" ``` ```bash docker compose exec -T elasticsearch curl -X DELETE "localhost:9200/your_index_name" ``` ## Memory and heap tuning `ES_JAVA_OPTS=-Xms512m -Xmx512m` in `elasticsearch/compose.yml` caps the JVM heap at 512MB, fine for local dev with a handful of small indices but tight once you're indexing real datasets. Raise both values (keep them equal to avoid heap resizing pauses) and rebuild: ```yaml - "ES_JAVA_OPTS=-Xms2g -Xmx2g" ``` ```bash ./laradock rebuild elasticsearch ``` ```bash docker compose build elasticsearch ``` As a rule of thumb, never set the heap above 50% of the Docker host's available RAM, and never above roughly 32GB even on a large machine (the JVM loses compressed-pointer optimizations past that point). ## Common issues - **Container exits immediately or fails healthcheck.** Elasticsearch needs `vm.max_map_count` to be at least `262144` on the Docker host. On Linux, set it with `sysctl -w vm.max_map_count=262144`; Docker Desktop on macOS/Windows usually handles this for you. - **`bootstrap.memory_lock` warnings.** The compose file sets `memlock` ulimits to unlimited already; if your Docker daemon still refuses to lock memory, check your host's own ulimits. - **Out-of-memory kills under load.** Heap is fixed at 512MB via `ES_JAVA_OPTS` in `elasticsearch/compose.yml`. Raise it (see [Memory and heap tuning](#memory-and-heap-tuning) above) if you're indexing large datasets locally. - **Cluster health stuck on `yellow`.** Expected on a single-node cluster, replica shards can never be assigned with only one node. Only `red` means an actual problem (a missing primary shard). - **Can't reach it from another container.** Use the container name `elasticsearch` as the host, not `localhost`, from inside `workspace` or `php-fpm`. --- Need a UI to browse indices? See **[Dejavu](https://laradock.io/docs/services/dejavu)**. Need dashboards? See **[Kibana](https://laradock.io/docs/services/kibana)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Kibana Source: https://laradock.io/docs/services/kibana ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Kibana? [Kibana](https://www.elastic.co/kibana) is the official visualization and dashboard UI for Elasticsearch. It lets you explore indices, build charts, and query data through a web interface instead of the raw REST API. Laradock builds it from the official image, version-matched to Elasticsearch. ## Start Kibana ```bash ./laradock start kibana ``` ```bash docker compose up -d kibana ``` `kibana/compose.yml` lists `elasticsearch` as a `depends_on`, so it starts automatically alongside Kibana, it has nothing to visualize without it. ## Stop Kibana ```bash ./laradock stop kibana ``` ```bash docker compose stop kibana ``` To delete the container: ```bash ./laradock remove kibana ``` ```bash docker compose rm -sf kibana ``` ## Configuration Laradock builds the image from `kibana/Dockerfile` using the shared `ELK_VERSION` variable in the root `.env` (the same version used for `elasticsearch`), plus this setting in `kibana/defaults.env`: | Variable | Default | What it does | |---|---|---| | `KIBANA_HTTP_PORT` | `5601` | Host-side port Kibana is published on (container port `5601`). | ## Change the Kibana version Kibana has no version variable of its own, it always builds against the shared `ELK_VERSION` in the root `.env` (Elastic requires matching major/minor versions across the stack): ```env ELK_VERSION=8.15.0 ``` Then rebuild both, since a mismatch between them causes Kibana to refuse to start: ```bash ./laradock rebuild kibana elasticsearch ``` ```bash docker compose build kibana elasticsearch ``` ## Connect Open [http://localhost:5601](http://localhost:5601) in your browser. Kibana auto-detects the `elasticsearch` container over the internal `backend` network, no manual host configuration needed for the bundled setup. There's no login screen. Laradock's `elasticsearch/compose.yml` sets `xpack.security.enabled=false`, so Kibana connects to Elasticsearch anonymously and drops you straight into the app, this is meant for local development, not a setup you'd expose publicly as-is. ## Kibana has no data of its own Kibana itself is stateless: it has no data volume in `kibana/compose.yml`. Everything you build in it, index patterns, saved searches, dashboards, visualizations, is stored by Elasticsearch itself, inside its own `.kibana` system index, on the `elasticsearch` volume. There's nothing to back up or wipe on the Kibana side specifically: to back up or reset your dashboards, back up or reset the underlying Elasticsearch data (see the **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)** page). Removing or rebuilding the `kibana` container never touches your saved objects, only removing the `elasticsearch` container's data volume does. ## Common issues - **Kibana shows "Kibana server is not ready yet".** It waits on Elasticsearch to be reachable and healthy first; confirm `elasticsearch` is actually up with `docker compose ps` and check `./laradock logs elasticsearch`. - **Version mismatch errors.** Kibana and Elasticsearch both read `ELK_VERSION` from the root `.env`, so they build to the same version automatically. If you changed one manually, rebuild both: `./laradock rebuild kibana elasticsearch`. - **Port already in use on your host.** Change `KIBANA_HTTP_PORT` in `.env` and restart: `./laradock restart kibana`. - **Dashboards/saved objects disappeared.** They live in Elasticsearch, not Kibana, check that you didn't wipe the `elasticsearch` data volume or point at a different `DATA_PATH_HOST`. --- Need a lighter-weight index browser instead? See **[Dejavu](https://laradock.io/docs/services/dejavu)**. Need the underlying engine? See **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MeiliSearch Source: https://laradock.io/docs/services/meilisearch ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MeiliSearch? [MeiliSearch](https://www.meilisearch.com) is a fast, open-source search engine built for developer experience: typo tolerance, instant results, and a simple REST API. It's a popular [Laravel Scout](https://laravel.com/docs/scout) driver for adding full-text search without the operational overhead of Elasticsearch. ## Start MeiliSearch ```bash ./laradock start meilisearch ``` ```bash docker compose up -d meilisearch ``` Your indexes are created on first start and kept between restarts under `DATA_PATH_HOST/meilisearch`. Name any other services alongside it to start them together, for example `./laradock start meilisearch workspace`. ## Stop MeiliSearch Stopping just pauses the container; **your indexes are safe**: ```bash ./laradock stop meilisearch ``` ```bash docker compose stop meilisearch ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove meilisearch ``` ```bash docker compose rm -sf meilisearch ``` ## Configuration All settings live in `meilisearch/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `MEILISEARCH_HOST_PORT` | `7700` | Host-side port MeiliSearch is published on (container port `7700`). | | `MEILISEARCH_KEY` | `masterkey` | Passed to the container as `MEILI_MASTER_KEY`, the admin key for the instance. | Note the image itself isn't version-pinned in `meilisearch/compose.yml`, it always pulls `getmeili/meilisearch:latest`. ## Connect Open [http://localhost:7700](http://localhost:7700) for the built-in web UI, or point Laravel Scout / any HTTP client at that same URL with the master key `masterkey` (or your own `MEILISEARCH_KEY`) as the API key. From another container use `http://meilisearch:7700`. ## Check health and stats Before debugging a "search isn't working" issue in your app, confirm the engine itself is healthy: ```bash curl http://localhost:7700/health curl http://localhost:7700/version curl -H "Authorization: Bearer masterkey" http://localhost:7700/stats ``` `/health` returns `{"status":"available"}` when it's ready to take requests. `/stats` (needs the master key) reports database size and per-index document counts, useful for spotting an index that silently stopped growing or a database approaching disk limits. ## Backup and restore MeiliSearch's entire database (indexes, settings, tasks) lives in the single folder mounted at `DATA_PATH_HOST/meilisearch` (container path `/data.ms`), so the simplest reliable backup is a filesystem copy taken while the container is stopped: ```bash ./laradock stop meilisearch ``` ```bash docker compose stop meilisearch ``` ```bash cp -a "${DATA_PATH_HOST:-~/.laradock/data}/meilisearch" ./meilisearch-backup ``` Then start it back up: ```bash ./laradock start meilisearch ``` ```bash docker compose up -d meilisearch ``` To restore, stop the container, replace the contents of `DATA_PATH_HOST/meilisearch` with your backup folder, then start it again. For a live backup without downtime, MeiliSearch also exposes a [dumps API](https://www.meilisearch.com/docs/reference/api/dump) (`POST /dumps`), useful when you can't afford to stop the container but want a point-in-time export. ## Start completely fresh (wipe all data) To throw away every index and start MeiliSearch from a clean, empty state (⚠️ this **permanently deletes** everything in this instance, back up first if you need anything): ```bash ./laradock stop meilisearch ./laradock remove meilisearch rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/meilisearch" ./laradock start meilisearch ``` ```bash docker compose stop meilisearch docker compose rm -sf meilisearch rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/meilisearch" docker compose up -d meilisearch ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where MeiliSearch's indexes actually live on your machine. After this, re-index your app's searchable models (for Laravel Scout, `php artisan scout:import "App\\Models\\YourModel"`). ## Pin a specific version `meilisearch/compose.yml` always pulls `getmeili/meilisearch:latest`, there's no `MEILISEARCH_VERSION` variable to set in `.env`. For a reproducible setup, edit the `image:` line in `meilisearch/compose.yml` directly to a specific tag, for example `getmeili/meilisearch:v1.9`, then rebuild: ```bash ./laradock rebuild meilisearch ``` ```bash docker compose build meilisearch ``` ## Talk to this search index from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this MeiliSearch by container name out of the box. Easiest fix: publish the port (already done, `MEILISEARCH_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `meilisearch`, for example `MEILISEARCH_HOST=http://host.docker.internal:7700` (Docker Desktop). Make sure the two projects use different `MEILISEARCH_HOST_PORT` values if they're both running at once. ## Common issues - **401/403 on every request.** You need the master key as a Bearer token (`Authorization: Bearer masterkey`) for any write or protected endpoint. - **Master key changed but old key still works, or vice versa.** MeiliSearch reads `MEILI_MASTER_KEY` at container start; restart the container (`./laradock restart meilisearch`) after changing `MEILISEARCH_KEY` in `.env`. - **Image updates unexpectedly.** Because `meilisearch/compose.yml` pins `:latest` rather than reading a version variable, a plain `docker compose pull` can bump you to a new MeiliSearch major version. [Pin a specific tag](#pin-a-specific-version) yourself if you need reproducibility. - **Index looks stale or empty after a Scout sync.** Check `/stats` (see [Check health and stats](#check-health-and-stats)) to confirm documents actually landed, then re-run `php artisan scout:import` for the affected model. - **App can't connect but the container is running.** Use the container name `meilisearch`, not `localhost`, from inside another container. --- Prefer typo-tolerant search with more filtering options? See **[Typesense](https://laradock.io/docs/services/typesense)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # OpenSearch Source: https://laradock.io/docs/services/opensearch ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is OpenSearch? [OpenSearch](https://opensearch.org) is the Apache-2.0 open-source fork of Elasticsearch, created and maintained by AWS after Elastic changed Elasticsearch's license. It provides the same search-and-analytics engine feature set with a REST API that's largely compatible with Elasticsearch clients. Laradock runs it as a single-node container with the security plugin disabled for local development. ## Start OpenSearch ```bash ./laradock start opensearch ``` ```bash docker compose up -d opensearch ``` Your indices are created as you use OpenSearch and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start opensearch workspace`. ## Stop OpenSearch Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop opensearch ``` ```bash docker compose stop opensearch ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove opensearch ``` ```bash docker compose rm -sf opensearch ``` ## Configuration All settings live in `opensearch/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `OPENSEARCH_VERSION` | `2` | Image tag from the [`opensearchproject/opensearch`](https://hub.docker.com/r/opensearchproject/opensearch) Docker Hub image. | | `OPENSEARCH_HOST_PORT` | `9202` | Host-side port for the REST API (container port `9200`). | | `OPENSEARCH_MONITORING_PORT` | `9600` | Host-side port for the monitoring/performance-analyzer endpoint (container port `9600`). | `opensearch/compose.yml` also runs it single-node (`discovery.type=single-node`), with `DISABLE_SECURITY_PLUGIN=true` and JVM heap capped at `-Xms512m -Xmx512m` via `OPENSEARCH_JAVA_OPTS`. ## Connect ```bash curl http://localhost:9202 ``` That returns the cluster/version info if it's up. From another container (e.g. `workspace`), use `http://opensearch:9200`, note the container listens on `9200` internally regardless of the host-side `OPENSEARCH_HOST_PORT` mapping. ## Check cluster and index health Cluster status (`green`/`yellow`/`red`): ```bash curl http://localhost:9202/_cluster/health?pretty ``` List every index with its size and document count: ```bash curl http://localhost:9202/_cat/indices?v ``` On a single-node cluster (Laradock's default), status usually sits at `yellow` rather than `green`, that's expected: `yellow` means replica shards are unassigned, which is normal when there's only one node to hold them. ## Raise the JVM heap size The default heap (`-Xms512m -Xmx512m`, set via `OPENSEARCH_JAVA_OPTS`) is fine for small local indices but gets tight once you're indexing real datasets. It's set directly in `opensearch/compose.yml`, not exposed as a `.env` variable, so edit it there: ```yaml - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g" ``` Keep `Xms` and `Xmx` equal (avoids the JVM resizing the heap at runtime), and stay under half your Docker host's available RAM, OpenSearch's own guidance for the JVM heap. Apply the change: ```bash ./laradock restart opensearch ``` ```bash docker compose restart opensearch ``` ## Backup and restore OpenSearch's snapshot API needs a filesystem repository path registered up front (`path.repo`), which isn't configured in Laradock's default `compose.yml`. The simplest reliable backup for a local single-node setup is to copy the data folder directly while the container is stopped, since indices are just files under `DATA_PATH_HOST/opensearch`. **Back up:** ```bash ./laradock stop opensearch ``` ```bash docker compose stop opensearch ``` ```bash tar -czf opensearch-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" opensearch ``` **Restore** into a fresh container (⚠️ this overwrites whatever is currently in the data folder): ```bash ./laradock stop opensearch ``` ```bash docker compose stop opensearch ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/opensearch" tar -xzf opensearch-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}" ``` ```bash ./laradock start opensearch ``` ```bash docker compose up -d opensearch ``` ## Start completely fresh (wipe all data) To throw away every index and start OpenSearch from a clean, empty state (⚠️ this **permanently deletes** all data in this container, back up first if you need anything): ```bash ./laradock stop opensearch ./laradock remove opensearch rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/opensearch" ./laradock start opensearch ``` ```bash docker compose stop opensearch docker compose rm -sf opensearch rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/opensearch" docker compose up -d opensearch ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where OpenSearch's indices actually live on your machine. ## Talk to this OpenSearch from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this OpenSearch by container name out of the box. Easiest fix: publish the port (already done, `OPENSEARCH_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `opensearch`, for example `host.docker.internal:9202` (Docker Desktop). Make sure the two projects use different `OPENSEARCH_HOST_PORT` values if they're both running at once. ## Common issues - **Port clash with `elasticsearch`.** If you're running both search engines side by side, `OPENSEARCH_HOST_PORT` (`9202`) is intentionally different from Elasticsearch's `9200` so they don't collide. - **Container exits or fails to start.** Like Elasticsearch, OpenSearch needs `vm.max_map_count >= 262144` on the Docker host (`sysctl -w vm.max_map_count=262144` on Linux). - **Security plugin is off.** `DISABLE_SECURITY_PLUGIN=true` means no authentication on the REST API by default, fine for local dev, not something to carry into production. - **Cluster status stuck at `yellow`.** Expected on a single-node cluster, see [Check cluster and index health](#check-cluster-and-index-health) above, it's not a sign anything is broken. - **App can't connect but the container is running.** Use the container name `opensearch`, not `localhost`, from inside another container. --- Looking for the original Elasticsearch instead? See **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Typesense Source: https://laradock.io/docs/services/typesense ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Typesense? [Typesense](https://typesense.org) is a fast, typo-tolerant open-source search engine and a drop-in [Laravel Scout](https://laravel.com/docs/scout) driver. It's designed to be simple to run and tune compared to Elasticsearch, with sensible defaults for instant, as-you-type search. ## Start Typesense ```bash ./laradock start typesense ``` ```bash docker compose up -d typesense ``` Your data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start typesense workspace`. ## Stop Typesense Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop typesense ``` ```bash docker compose stop typesense ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/typesense`): ```bash ./laradock remove typesense ``` ```bash docker compose rm -sf typesense ``` ## Configuration All settings live in `typesense/defaults.env` and can be overridden by adding the same line to your own `.env` (your `.env` always wins): | Variable | Default | What it does | |---|---|---| | `TYPESENSE_VERSION` | `30.2` | Image tag from the [`typesense/typesense`](https://hub.docker.com/r/typesense/typesense) Docker Hub image. | | `TYPESENSE_HOST_PORT` | `8108` | Host-side port Typesense is published on (container port `8108`). | | `TYPESENSE_API_KEY` | `typesense` | API key required on every request; change it for anything beyond local dev. | | `TYPESENSE_ENABLE_CORS` | `true` | Whether to allow cross-origin requests, useful when calling the API directly from a browser-based frontend. | ## Change the Typesense version Set the version in your `.env`: ```env TYPESENSE_VERSION=27.1 ``` Then apply the change: ```bash ./laradock rebuild typesense ``` ```bash docker compose build typesense ``` If you're crossing a major version, take a [snapshot](#backup-and-restore-snapshots) first. Data compatibility across major Typesense versions isn't guaranteed, so having a restorable backup before you upgrade is the safe move. ## Change the API key Set a new key in your `.env`: ```env TYPESENSE_API_KEY=your-own-long-random-key ``` Then restart so the container picks it up: ```bash ./laradock restart typesense ``` ```bash docker compose restart typesense ``` Update every client (your app's `.env`, Laravel Scout config, any other Laradock project pointed at this instance) with the new key, they'll get `401`s until they match. ## Connect The API is available at [http://localhost:8108](http://localhost:8108). Check it's up with: ```bash curl http://localhost:8108/health ``` Every request needs the API key, sent as the `X-TYPESENSE-API-KEY` header. From another container use `http://typesense:8108`. ## Check cluster health and stats Beyond the basic `/health` check above, Typesense exposes two more useful endpoints, both need the API key header: ```bash curl -H "X-TYPESENSE-API-KEY: typesense" http://localhost:8108/stats.json ``` Returns request latency and rate stats (searches, writes, imports per second). ```bash curl -H "X-TYPESENSE-API-KEY: typesense" http://localhost:8108/metrics.json ``` Returns system-level metrics for the container: CPU, memory, disk, and network usage. Useful for spotting a collection that's outgrown its container's memory before it starts throwing errors. ## List your collections ```bash curl -H "X-TYPESENSE-API-KEY: typesense" http://localhost:8108/collections ``` Returns every collection (Typesense's equivalent of a table/index) with its schema and document count, handy for confirming Laravel Scout actually created the collection you expect. ## Backup and restore (snapshots) Typesense's built-in snapshot mechanism is the supported way to back up: it writes a consistent point-in-time copy of `/data` to a path you choose inside the container. It's just an HTTP call, no need to open a shell in the container, run it from your host: ```bash curl -X POST -H "X-TYPESENSE-API-KEY: typesense" \ "http://localhost:8108/operations/snapshot?snapshot_path=/data/snapshots/$(date +%Y%m%d)" ``` This creates the snapshot under `/data/snapshots/...` inside the container, which is `DATA_PATH_HOST/typesense/snapshots/...` on your host since `/data` is the mounted volume. Copy that folder out (or back it up like any other file) to keep it safe. To restore, stop the container, replace the contents of `DATA_PATH_HOST/typesense` on your host with a snapshot folder's contents, then start it again: ```bash ./laradock stop typesense ``` ```bash docker compose stop typesense ``` ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/typesense" cp -r "${DATA_PATH_HOST:-~/.laradock/data}/typesense/snapshots/20260710" "${DATA_PATH_HOST:-~/.laradock/data}/typesense" ``` ```bash ./laradock start typesense ``` ```bash docker compose up -d typesense ``` ## Start completely fresh (wipe all data) To throw away every collection and start Typesense from a clean, empty state (this **permanently deletes** everything, take a [snapshot](#backup-and-restore-snapshots) first if you need anything): ```bash ./laradock stop typesense ./laradock remove typesense rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/typesense" ./laradock start typesense ``` ```bash docker compose stop typesense docker compose rm -sf typesense rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/typesense" docker compose up -d typesense ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default), so the folder above is where every Typesense collection actually lives on your machine. After this, re-run whatever seeds/imports your app uses to rebuild collections (e.g. Laravel Scout's `php artisan scout:import`). ## Talk to this from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this Typesense by container name out of the box. Easiest fix: publish the port (already done, `TYPESENSE_HOST_PORT`) and have the other project connect to your **host machine's** address instead of `typesense`, for example `TYPESENSE_HOST=host.docker.internal` (Docker Desktop) with the port set to this project's `TYPESENSE_HOST_PORT`, and the matching `TYPESENSE_API_KEY`. Make sure the two projects use different `TYPESENSE_HOST_PORT` values if they're both running at once. ## Common issues - **401 on every request.** Missing or wrong `X-TYPESENSE-API-KEY` header, check it matches `TYPESENSE_API_KEY`. - **Browser requests blocked by CORS.** Confirm `TYPESENSE_ENABLE_CORS=true` (the default) if you're calling the API directly from frontend JavaScript rather than through your backend. - **API key changes don't take effect.** Restart the container after changing `TYPESENSE_API_KEY` in `.env`: `./laradock restart typesense`. - **App can't connect but the container is running.** Use the container name `typesense`, not `localhost`, from inside another container. - **Port already in use on your host.** Another local Typesense (or another Laradock project) is already bound to `8108`. Change `TYPESENSE_HOST_PORT` in `.env` and restart: `./laradock restart typesense`. --- Prefer a search engine with a broader plugin ecosystem? See **[Elasticsearch](https://laradock.io/docs/services/elasticsearch)** or **[MeiliSearch](https://laradock.io/docs/services/meilisearch)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # AWS EB CLI Source: https://laradock.io/docs/services/aws-eb-cli ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is the AWS EB CLI? The [AWS Elastic Beanstalk CLI](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3.html) (`eb`) is Amazon's command-line tool for initializing, configuring, and deploying applications to Elastic Beanstalk. Laradock packages it in its own container (built on `python:slim` with `awsebcli` installed via pip), so you get a working `eb` command without installing Python or the CLI on your host. Unlike most Laradock services, this isn't a long-running server, it's a CLI tool container you shell into on demand, similar to the workspace tools. ## Start the container ```bash ./laradock start aws ``` ```bash docker compose up -d aws ``` The container depends on `workspace` and shares its `APP_CODE_PATH_HOST` mount, so your project files are available inside it at the same path as in `workspace`. ## Enter it and use `eb` ```bash ./laradock enter aws eb init ``` ```bash docker compose exec aws bash eb init ``` Follow the [EB CLI configuration docs](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-configuration.html) from there (`eb create`, `eb deploy`, `eb status`, etc.) exactly as you would with a host-installed EB CLI. ## AWS credentials `eb init` (or a plain `aws configure`) prompts for your AWS access key, secret key, and region, then writes them to `/root/.aws/` **inside the container**. Since `aws-eb-cli/compose.yml` doesn't mount a home directory by default, those credentials live only in that container's filesystem: running `./laradock remove aws` deletes them, and you'll be prompted again next time you `eb init` after a fresh `./laradock start aws`. To persist credentials across container removals/rebuilds, mount your host's `~/.aws` folder in `aws-eb-cli/compose.yml`: ```yaml volumes: - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER}${APP_CODE_CONTAINER_FLAG} - ~/.aws:/root/.aws ``` Then [rebuild](#ssh-keys) or just recreate the container for the new volume to take effect. This also means any AWS CLI profile you already have configured on your host becomes available inside the container automatically. ## Stop the container Stopping just pauses the container; the `.elasticbeanstalk/config.yml` written by `eb init` lives in your mounted project folder, not the container, so it's safe either way: ```bash ./laradock stop aws ``` ```bash docker compose stop aws ``` Since this container doesn't do anything on its own between commands, it's fine to leave it stopped and only start it when you need to run `eb` commands. To delete the container entirely (see [AWS credentials](#aws-credentials) above for what that means for anything you configured without the `~/.aws` mount): ```bash ./laradock remove aws ``` ```bash docker compose rm -sf aws ``` ## SSH keys Elastic Beanstalk environments are typically accessed over SSH, so before building the image, add the keys you want available inside the container to the `aws-eb-cli/ssh_keys` folder. The Dockerfile copies everything in that folder into `/root/.ssh/` at build time and sets correct permissions (`600` for private keys, `644` for `.pub` files). ```bash ./laradock rebuild aws ``` ```bash docker compose build aws ``` ## Configuration There's no `aws-eb-cli/defaults.env`, this service has no Laradock-level environment variables to configure. All configuration happens through `eb init`/`eb config` (which write to `.elasticbeanstalk/config.yml` in your project) or through AWS credentials you provide inside the container (see [AWS credentials](#aws-credentials) above). ## Common issues - **SSH key changes don't show up in the container.** SSH keys are copied in at build time, not mounted, rebuild after adding or changing keys: `./laradock rebuild aws`. - **`eb` can't find your project.** Run `eb init` from inside `APP_CODE_PATH_CONTAINER` (your project root as mounted in the container), the same path `workspace` uses. - **AWS credentials aren't picked up.** The container doesn't inject AWS credentials automatically; configure them the same way you would for the EB CLI anywhere else, via `eb init`'s prompts or standard AWS credential files/env vars. - **Credentials disappear after `./laradock remove aws`.** Expected unless you've mounted `~/.aws` as described in [AWS credentials](#aws-credentials), the container has no persistent storage of its own for them. --- Need a general dev shell instead? See the **[Workspace guide](https://laradock.io/docs/services/workspace)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Blackfire Source: https://laradock.io/docs/services/blackfire ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Blackfire? [Blackfire](https://www.blackfire.io) is a PHP (and web) performance profiler from the SensioLabs/Symfony team: it traces function calls, memory, I/O, and SQL to help you find bottlenecks. It's a hosted SaaS product, the agent Laradock runs locally only collects and forwards profiling data to your Blackfire.io account. ## Start Blackfire ```bash ./laradock start blackfire ``` ```bash docker compose up -d blackfire ``` The `blackfire` container depends on `php-fpm`. It only collects data when a profiling run is triggered from a PHP process with the Blackfire probe enabled, it doesn't serve anything on its own. ## Stop Blackfire ```bash ./laradock stop blackfire ``` ```bash docker compose stop blackfire ``` There's no data to lose when it stops, the agent only relays profiles as they happen, it doesn't store anything on disk. ## Configuration `blackfire/defaults.env` holds the credentials for the agent container itself: | Variable | Default | What it does | |---|---|---| | `BLACKFIRE_SERVER_ID` | `` | Server ID from your Blackfire.io account (Settings β†’ Credentials). | | `BLACKFIRE_SERVER_TOKEN` | `` | Server token paired with the above. | You need a [Blackfire.io account](https://blackfire.io) to get real values, the placeholders won't authenticate. Set both in your `.env` before starting the container. There's a second pair of credentials, `BLACKFIRE_CLIENT_ID`/`BLACKFIRE_CLIENT_TOKEN`, set in `workspace/defaults.env`. Those are for the Blackfire *probe*/CLI baked into `php-fpm`/`workspace` at build time (via `INSTALL_BLACKFIRE=true`), not the agent container, and they authenticate the actual profiling client, not just the agent relay. ## Enable profiling on PHP The agent alone isn't enough, `php-fpm` (or `workspace`, for CLI profiling) needs the Blackfire probe extension installed, which only happens if `INSTALL_XDEBUG=false` and `INSTALL_BLACKFIRE=true` at build time: ```env INSTALL_BLACKFIRE=true BLACKFIRE_CLIENT_ID=your_client_id BLACKFIRE_CLIENT_TOKEN=your_client_token BLACKFIRE_SERVER_ID=your_server_id BLACKFIRE_SERVER_TOKEN=your_server_token ``` Rebuild the images so the probe gets installed: ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Then start (or restart) the containers so they pick up the new build and credentials: ```bash ./laradock start blackfire php-fpm workspace ``` ```bash docker compose up -d blackfire php-fpm workspace ``` Xdebug and the Blackfire probe can't run in the same PHP process, if `INSTALL_XDEBUG=true`, the Blackfire probe install step is skipped even when `INSTALL_BLACKFIRE=true`. ## Run a profile With `INSTALL_BLACKFIRE=true`, the `blackfire` CLI binary is installed inside `workspace` alongside the probe. Profile an HTTP request against your app: ```bash ./laradock enter workspace blackfire curl http://php-fpm/ ``` Or profile a CLI script (an Artisan command, a queue worker, a one-off script): ```bash ./laradock enter workspace blackfire run php artisan your:command ``` Either way, a link to the profile's results on your Blackfire.io dashboard prints to the terminal when it finishes. For profiling real user traffic on a running app instead of one-off CLI calls, use the [Blackfire browser extension or the `X-Blackfire-Query` trigger](https://docs.blackfire.io/profiling-cookbooks/profiling-http) against your app's URL, both talk straight to the probe inside `php-fpm`, the agent container just relays the result. ## Applying new credentials without a rebuild Only `BLACKFIRE_SERVER_ID`/`BLACKFIRE_SERVER_TOKEN` (read by the `blackfire` container at runtime) can be changed by restarting alone. `BLACKFIRE_CLIENT_ID`/`BLACKFIRE_CLIENT_TOKEN` are baked into `workspace`/`php-fpm` at build time, changing those needs the rebuild above, not just a restart. ```bash ./laradock restart blackfire ``` ```bash docker compose restart blackfire ``` ## Common issues - **Nothing shows up in your Blackfire.io dashboard.** Double-check all four credentials (`BLACKFIRE_SERVER_ID`/`TOKEN` for the agent, `BLACKFIRE_CLIENT_ID`/`TOKEN` for the probe), a mismatch on either pair silently fails to relay profiles. - **Profiling extension isn't loaded in PHP.** Confirm `INSTALL_BLACKFIRE=true` was set *before* building `php-fpm`/`workspace`, and that `INSTALL_XDEBUG` is `false`, then rebuild: `./laradock rebuild php-fpm workspace`. - **Probe can't reach the agent.** The probe is hardcoded to talk to `tcp://blackfire:8707`, the `blackfire` container's name and internal port on the Laradock network. If you renamed the service in your own compose override, the probe won't find it. - **Placeholder credentials left in `.env`.** The defaults (``, ``, etc.) are non-functional placeholders, replace them with real values from your Blackfire.io account before expecting profiles to appear. - **Changed `BLACKFIRE_CLIENT_ID`/`TOKEN` but nothing changed.** Those are build-time values on `workspace`/`php-fpm`, not runtime ones. Edit `.env`, then rebuild those two images (see [Applying new credentials](#applying-new-credentials-without-a-rebuild)) instead of just restarting. --- Profiling instead with step debugging? See the **[PHP-FPM guide](https://laradock.io/docs/services/php-fpm)** for `INSTALL_XDEBUG`. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Confluence Source: https://laradock.io/docs/services/confluence ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Confluence? [Confluence](https://www.atlassian.com/software/confluence) is Atlassian's team wiki and documentation platform. Laradock runs it via the official `atlassian/confluence-server` image, backed by the `postgres` container. > Confluence is a licensed Atlassian product. You'll need an evaluation or paid license from Atlassian to get past initial setup. ## Start Confluence Confluence depends on `postgres` (its `compose.yml` declares it), so start both together: ```bash ./laradock start postgres confluence ``` ```bash docker compose up -d postgres confluence ``` ## Stop Confluence Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop confluence ``` ```bash docker compose stop confluence ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST/Confluence`): ```bash ./laradock remove confluence ``` ```bash docker compose rm -sf confluence ``` ## Configuration Settings live in `confluence/defaults.env` and can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `CONFLUENCE_VERSION` | `6.13-ubuntu-18.04-adoptopenjdk8` | Image tag from the [`atlassian/confluence-server` Docker Hub page](https://hub.docker.com/r/atlassian/confluence-server/). Pin this to control which Confluence version you run. | | `CONFLUENCE_HOST_HTTP_PORT` | `8090` | Host port Confluence is published on (container always listens on `8090` internally). | Confluence's database name, user, and password (`CONFLUENCE_POSTGRES_DB`, `CONFLUENCE_POSTGRES_USER`, `CONFLUENCE_POSTGRES_PASSWORD`) live in `postgres/defaults.env` (default `laradock_confluence` for all three), which also sets `CONFLUENCE_POSTGRES_INIT=true` so the database and role are created automatically the first time `postgres` initializes its data folder. Application data (attachments, indexes, config) persists under `DATA_PATH_HOST/Confluence`. ## First-time setup Start Confluence and `postgres` together (see [Start Confluence](#start-confluence) above), then open [http://localhost:8090](http://localhost:8090) and walk through Confluence's own setup wizard: license entry, database connection (point it at the `postgres` container using the `CONFLUENCE_POSTGRES_*` credentials above), and initial admin account. ## Serve it through NGINX with SSL 1. Copy `nginx/sites/confluence.conf.example` to a new file in the same folder and replace the sample domain with yours. 2. Configure SSL keys for your domain (see the [NGINX guide](https://laradock.io/docs/services/nginx) for certificate setup). Confluence stays reachable directly on `8090` regardless, NGINX just adds a proper domain and TLS in front of it. ## Backup and restore Confluence's state is split across two places: application data (attachments, indexes, config) on disk, and content/permissions in its `postgres` database. Back up both. **Back up the application data** to a `.tar.gz` on your host: ```bash tar -czf confluence-data-backup.tar.gz -C "${DATA_PATH_HOST:-~/.laradock/data}/Confluence" . ``` **Back up the database**: ```bash ./laradock exec -T postgres pg_dump -U laradock_confluence laradock_confluence > confluence-db-backup.sql ``` ```bash docker compose exec -T postgres pg_dump -U laradock_confluence laradock_confluence > confluence-db-backup.sql ``` Replace the database/user names if you changed `CONFLUENCE_POSTGRES_DB`/`CONFLUENCE_POSTGRES_USER`. The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file. **Restore** is the reverse: stop Confluence, extract the `.tar.gz` back into `DATA_PATH_HOST/Confluence`, restore the database, then start Confluence again: ```bash ./laradock exec -T postgres psql -U laradock_confluence -d laradock_confluence -f - < confluence-db-backup.sql ``` ```bash docker compose exec -T postgres psql -U laradock_confluence -d laradock_confluence -f - < confluence-db-backup.sql ``` ## Start completely fresh (wipe all data) To throw away everything and re-run Confluence's setup wizard from scratch (⚠️ this **permanently deletes** all pages, attachments, and the Confluence database, back up first if you need anything): ```bash ./laradock stop confluence ./laradock remove confluence rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/Confluence" ``` ```bash docker compose stop confluence docker compose rm -sf confluence rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/Confluence" ``` Wiping the application data folder alone leaves the old content sitting in the `postgres` database, so the setup wizard will find an existing schema instead of starting fresh. Drop and recreate the database too (using the `postgres` root credentials, `default`/`secret` by default): ```bash ./laradock enter postgres ``` ```bash docker compose exec postgres bash ``` ```bash dropdb -U default laradock_confluence createdb -U default -O laradock_confluence laradock_confluence exit ``` Then start Confluence again (see [Start Confluence](#start-confluence)) and go through the setup wizard once more. ## Change the Confluence version Set the version in your `.env`: ```env CONFLUENCE_VERSION=7.19.24-jdk11 ``` Then recreate the container, which pulls the new image tag automatically: ```bash ./laradock start confluence ``` ```bash docker compose up -d confluence ``` Confluence runs its own database migration on first boot after a version bump, so [back up both the application data and the database](#backup-and-restore) before changing major versions, the same way you would for any upgrade with irreversible schema changes. ## Common issues - **Setup wizard asks for a license every restart.** That means `DATA_PATH_HOST/Confluence` isn't persisting between restarts, check your `DATA_PATH_HOST` value and that the volume actually mounted. - **Confluence can't connect to its database.** Confirm `postgres` is running and that `CONFLUENCE_POSTGRES_INIT=true` was set the first time `postgres` initialized, that flag only creates the database/role on first boot. - **Container takes a long time to become reachable.** This is normal for Confluence, it's a JVM application with a real startup sequence; check `./laradock logs confluence` before assuming it's stuck. - **Port already in use on your host.** Change `CONFLUENCE_HOST_HTTP_PORT` in `.env` and restart: `./laradock restart confluence`. --- Fronting it with a domain and TLS? See the **[NGINX guide](https://laradock.io/docs/services/nginx)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Keycloak Source: https://laradock.io/docs/services/keycloak ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Keycloak? [Keycloak](https://www.keycloak.org) is an open-source identity and access management server: single sign-on, OAuth2/OpenID Connect, SAML, user federation, and admin consoles for managing realms and clients. Laradock runs it via the official [Bitnami Keycloak image](https://hub.docker.com/r/bitnami/keycloak), backed by the `postgres` container. ## Start Keycloak Keycloak needs `postgres` to store its realms, users, and clients, so start both together: ```bash ./laradock start postgres keycloak ``` ```bash docker compose up -d postgres keycloak ``` ## Stop Keycloak ```bash ./laradock stop keycloak ``` ```bash docker compose stop keycloak ``` Keycloak itself keeps no data on disk, everything (realms, users, clients) lives in the `postgres` database, so stopping or removing the `keycloak` container never touches your data. ## Configuration Settings live in `keycloak/defaults.env` and can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `KEYCLOAK_VERSION` | `latest` | Image tag from the [Bitnami Keycloak Docker Hub page](https://hub.docker.com/r/bitnami/keycloak/tags). | | `KEYCLOAK_HTTP_PORT` | `8081` | Host and container port Keycloak is published on. | | `KEYCLOAK_CREATE_ADMIN_USER` | `true` | Whether to auto-create the initial admin user on first boot. | | `KEYCLOAK_ADMIN_USER` | `admin` | Initial admin username. | | `KEYCLOAK_ADMIN_PASSWORD` | `secret` | Initial admin password. | | `KEYCLOAK_POSTGRES_HOST` | `postgres` | Hostname of the Postgres container Keycloak connects to. | The database name, user, and password (`KEYCLOAK_POSTGRES_DB`, `KEYCLOAK_POSTGRES_USER`, `KEYCLOAK_POSTGRES_PASSWORD`) aren't in `keycloak/defaults.env`, they live in the root `.env.example` (default `laradock_keycloak` for all three) and are passed into the `postgres` container, which auto-creates that database and role on first boot when `KEYCLOAK_POSTGRES_INIT=true` (set in `postgres/defaults.env`). ## Log in to the admin console Once both containers are up, open [http://localhost:8081](http://localhost:8081) (or your own `KEYCLOAK_HTTP_PORT`) and sign in with `admin` / `secret` (or your own `KEYCLOAK_ADMIN_USER`/`KEYCLOAK_ADMIN_PASSWORD`). ## Backup and restore Keycloak stores everything (realms, clients, users, credentials) in the `laradock_keycloak` database inside `postgres`, so backing it up means dumping that one database, the same way you would for any Postgres-backed app: ```bash ./laradock exec -T postgres pg_dump -U laradock_keycloak laradock_keycloak > keycloak-backup.sql ``` ```bash docker compose exec -T postgres pg_dump -U laradock_keycloak laradock_keycloak > keycloak-backup.sql ``` Replace `laradock_keycloak` with your own `KEYCLOAK_POSTGRES_USER`/`KEYCLOAK_POSTGRES_DB` if you changed them. The `-T` disables the container's pseudo-terminal so the dump isn't corrupted when redirected to a file. **Restore** into an existing (empty) `laradock_keycloak` database: ```bash ./laradock exec -T postgres psql -U laradock_keycloak laradock_keycloak < keycloak-backup.sql ``` ```bash docker compose exec -T postgres psql -U laradock_keycloak laradock_keycloak < keycloak-backup.sql ``` Restart Keycloak afterwards (`./laradock restart keycloak`) so it doesn't hold a stale connection to the database it was just restored into. ## Export and import individual realms For moving a single realm between environments (not a full database backup), Keycloak has its own realm export/import, independent of Postgres: - **From the admin console:** open a realm, go to **Realm settings β†’ Action β†’ Partial export**, and choose whether to include groups/roles and clients. This downloads a realm JSON file you can hand to a teammate or re-import elsewhere via **Realm settings β†’ Action β†’ Partial import**. - **From the command line** (full export including users, not available from the console): the image ships Keycloak's `kc.sh` script at `/opt/bitnami/keycloak/bin/kc.sh`. Exports and imports run in their own startup mode, so stop the server first: ```bash ./laradock stop keycloak ./laradock exec keycloak /opt/bitnami/keycloak/bin/kc.sh export --dir /tmp/export --realm myrealm ``` ```bash docker compose stop keycloak docker compose exec keycloak /opt/bitnami/keycloak/bin/kc.sh export --dir /tmp/export --realm myrealm ``` Copy the resulting JSON out of the container with `docker cp`, then import it the same way with `kc.sh import --dir /tmp/export` on the target environment before starting Keycloak again. ## Start completely fresh (wipe all data) Since Keycloak keeps no data of its own, wiping it means dropping and recreating its Postgres database (⚠️ this **permanently deletes** every realm, client, and user, back up first if you need anything): ```bash ./laradock exec postgres psql -U laradock_keycloak -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" laradock_keycloak ./laradock restart keycloak ``` ```bash docker compose exec postgres psql -U laradock_keycloak -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" laradock_keycloak docker compose restart keycloak ``` Keycloak re-runs its own first-boot database migrations and, if `KEYCLOAK_CREATE_ADMIN_USER=true`, re-seeds the initial admin user on the next start. ## Talk to this Keycloak from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project can't reach this Keycloak by container name out of the box, useful if you want one shared SSO server for several local apps. Point the other project's OIDC/SAML client at your **host machine's** address instead of `keycloak`, for example `http://host.docker.internal:8081` (Docker Desktop) using this project's `KEYCLOAK_HTTP_PORT`. Make sure only one Laradock project publishes that port at a time, or give each a unique `KEYCLOAK_HTTP_PORT`. ## Common issues - **Keycloak can't reach its database.** Confirm `postgres` is running (`docker compose ps postgres`) and that `KEYCLOAK_POSTGRES_INIT=true` was set the first time `postgres` initialized its data folder, that flag only creates the database/role on the very first boot. - **Admin login fails after changing credentials.** `KEYCLOAK_ADMIN_USER`/`KEYCLOAK_ADMIN_PASSWORD` only seed the admin account on first boot. Changing them later in `.env` doesn't update the existing user, change the password from inside the admin console instead. - **Port already in use.** Change `KEYCLOAK_HTTP_PORT` in `.env` and restart: `./laradock restart keycloak`. - **Changes disappear after `./laradock remove keycloak`.** That's expected, Keycloak keeps no local data; as long as `postgres` and its `laradock_keycloak` database are untouched, everything comes back on the next `./laradock start keycloak`. --- Need a general-purpose Postgres database instead? See the **[Databases guide](https://laradock.io/docs/Intro#supported-services)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Metabase Source: https://laradock.io/docs/services/metabase ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Metabase? [Metabase](https://www.metabase.com) is an open-source business intelligence tool: connect it to a database, and non-technical users can build charts and dashboards without writing SQL (though you still can, if you want to). Laradock runs it from the official `metabase/metabase:latest` image. ## Start Metabase ```bash ./laradock start metabase ``` ```bash docker compose up -d metabase ``` Its own application data is created on first start and kept between restarts. Name any other services alongside it to start them together, for example `./laradock start metabase mysql`. ## Stop Metabase Stopping just pauses the container; **your dashboards and questions are safe**: ```bash ./laradock stop metabase ``` ```bash docker compose stop metabase ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove metabase ``` ```bash docker compose rm -sf metabase ``` ## Configuration Settings live in `metabase/defaults.env` and can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `METABASE_PORT` | `3030` | Host port Metabase is published on (container always listens on `3000` internally). | | `METABASE_DB_FILE` | `metabase.db` | Filename for Metabase's own application database (an embedded H2 file, stores dashboards/questions/users, not your app data). | Metabase's application data persists under `DATA_PATH_HOST/metabase-data`, mounted into the container. Connecting Metabase to your actual app database (MySQL, Postgres, etc.) is done from Metabase's own admin UI after first boot, not via `.env`. ## First-time setup Start Metabase (see above), then open [http://localhost:3030](http://localhost:3030) and follow the setup wizard to create an admin account, then add a database connection. Inside Laradock, other containers are reachable by name (`mysql`, `postgres`, etc.), use those as the host, not `localhost`. See [Running Metabase on Docker](https://www.metabase.com/docs/latest/installation-and-operation/running-metabase-on-docker) for the full range of configuration options (email, SSO, embedding) beyond what Laradock wires up by default. ## Backup and restore Metabase stores everything it knows, dashboards, saved questions, users, and your database connections, in its own embedded H2 file under `DATA_PATH_HOST/metabase-data`. It has no `mysqldump`-style export command; back it up by copying that folder while Metabase is stopped, so the file isn't being written to mid-copy. **Back up:** ```bash ./laradock stop metabase ``` ```bash docker compose stop metabase ``` ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/metabase-data" ~/metabase-backup ``` **Restore** by copying a saved backup back into place before starting Metabase again: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/metabase-data" cp -r ~/metabase-backup "${DATA_PATH_HOST:-~/.laradock/data}/metabase-data" ``` Then start Metabase normally. This backs up Metabase's own configuration and saved dashboards only, it does **not** back up the app databases Metabase connects to, back those up separately (see the relevant database's own doc page). ## Start completely fresh (reset all dashboards, questions, and users) To throw away Metabase's admin account, connections, dashboards, and questions and go through the setup wizard again (⚠️ this **permanently deletes** everything above, back up first if you need anything): ```bash ./laradock stop metabase ./laradock remove metabase rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/metabase-data" ./laradock start metabase ``` ```bash docker compose stop metabase docker compose rm -sf metabase rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/metabase-data" docker compose up -d metabase ``` This only resets Metabase itself, none of the app databases it was connected to are touched. ## Common issues - **Setup wizard runs again after a restart.** Confirm `DATA_PATH_HOST/metabase-data` actually persisted, if that folder was deleted or `DATA_PATH_HOST` changed, Metabase starts with a fresh application database. - **Can't connect to your app's database from Metabase.** Use the container name (`mysql`, `postgres`, ...) as the host in Metabase's connection form, `localhost` from inside the `metabase` container refers to the Metabase container itself. - **Port already in use on your host.** Change `METABASE_PORT` in `.env` and restart: `./laradock restart metabase`. - **Metabase feels slow on first load.** This is normal, Metabase's JVM-based backend takes a bit longer to start than most containers; check `./laradock logs metabase` for `Metabase Initialization COMPLETE` before assuming it's stuck. --- Need the database Metabase is reporting on? See the **[Databases guide](https://laradock.io/docs/Intro#supported-services)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # MinIO Source: https://laradock.io/docs/services/minio ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MinIO? [MinIO](https://min.io) is an open-source, S3-compatible object storage server. Laradock runs it locally so you can develop against `AWS_*`-style filesystem code (Laravel's `s3` disk, presigned URLs, multipart uploads) without touching a real AWS bucket. ## Start MinIO ```bash ./laradock start minio ``` ```bash docker compose up -d minio ``` ## Stop MinIO Stopping just pauses the container; **your data is safe**: ```bash ./laradock stop minio ``` ```bash docker compose stop minio ``` To delete the container entirely (the data on disk is still untouched, it lives under `DATA_PATH_HOST`): ```bash ./laradock remove minio ``` ```bash docker compose rm -sf minio ``` ## Configuration Settings live in `minio/defaults.env` and can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `MINIO_PORT` | `9000` | Host port for the S3 API endpoint. | | `MINIO_CONSOLE_PORT` | `9001` | Host port for the MinIO web console. | | `MINIO_ROOT_USER` | `laradock` | Root access key (used as both username and S3 access key). | | `MINIO_ROOT_PASSWORD` | `laradock` | Root secret key (used as both password and S3 secret key). | Data is stored under `DATA_PATH_HOST/minio/data` (buckets/objects) and `DATA_PATH_HOST/minio/config` (server config), both mounted as volumes so they survive container restarts. Unlike MySQL's root credentials, MinIO's root user/password aren't a one-time first-boot setting: MinIO reads `MINIO_ROOT_USER`/`MINIO_ROOT_PASSWORD` from the environment on **every** startup, so changing them in `.env` and restarting takes effect immediately, even against existing data. ## Open the console and create a bucket Open [http://localhost:9001](http://localhost:9001) and log in with `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` (`laradock` / `laradock` by default). Create a bucket from the console UI, or from the [MinIO client](https://min.io/docs/minio/linux/reference/minio-mc.html) (`mc`) if you've installed it in the workspace container by setting `WORKSPACE_INSTALL_MC=true` in `.env` and rebuilding workspace: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then, inside the workspace shell: ```bash mc alias set local http://minio:9000 laradock laradock mc mb local/your-bucket ``` The S3 API itself is on port `9000` (`MINIO_PORT`), not `9001`, if you're testing the API directly with `curl` or an S3 client. ## Point a Laravel app at it ```env AWS_URL=http://minio:9000 AWS_ACCESS_KEY_ID=laradock AWS_SECRET_ACCESS_KEY=laradock AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET=your-bucket AWS_USE_PATH_STYLE_ENDPOINT=true ``` ```php 's3' => [ 'driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION'), 'bucket' => env('AWS_BUCKET'), 'endpoint' => env('AWS_URL'), 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), ], ``` `AWS_USE_PATH_STYLE_ENDPOINT=true` is required for local MinIO (it doesn't support virtual-hosted-style bucket addressing out of the box), don't carry it over to a real AWS S3 config. ## Backup and restore MinIO stores every bucket and object as plain files under `DATA_PATH_HOST/minio/data`, so the simplest reliable backup is a filesystem copy of that folder while the container is stopped: ```bash ./laradock stop minio ``` ```bash docker compose stop minio ``` ```bash cp -r "${DATA_PATH_HOST:-~/.laradock/data}/minio/data" ~/minio-backup ``` Then start it again: ```bash ./laradock start minio ``` ```bash docker compose up -d minio ``` **Restore** the same way, in reverse: stop MinIO, replace the contents of `DATA_PATH_HOST/minio/data` with your backup, then start it again. ## Start completely fresh (wipe all data) To throw away every bucket, object, and server config and start MinIO from a clean, empty state (⚠️ this **permanently deletes** everything, back up first if you need anything): ```bash ./laradock stop minio ./laradock remove minio rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/minio" ./laradock start minio ``` ```bash docker compose stop minio docker compose rm -sf minio rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/minio" docker compose up -d minio ``` `DATA_PATH_HOST` is whatever you have set in `.env` (`~/.laradock/data` by default). Deleting the `minio` folder removes both `data` (buckets/objects) and `config` (server state), so the next start is a genuinely fresh MinIO instance with no buckets and only the root user from `.env`. ## Talk to this bucket from another Laradock project Each Laradock project is its own isolated Docker network by default, so a second project's containers can't reach this MinIO by container name out of the box. Easiest fix: publish the port (already done, `MINIO_PORT`) and have the other project connect to your **host machine's** address instead of `minio`, for example `AWS_URL=http://host.docker.internal:9000` (Docker Desktop) using this project's `MINIO_PORT`. Make sure the two projects use different `MINIO_PORT`/`MINIO_CONSOLE_PORT` values if they're both running at once. ## Common issues - **App can't connect but the container is running.** Use `AWS_URL=http://minio:9000` (the container name), not `localhost`, that only works from your host machine, not from inside another container like `php-fpm` or `workspace`. - **"Access Denied" from the S3 API.** Double-check `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` in your app's `.env` match `MINIO_ROOT_USER`/`MINIO_ROOT_PASSWORD` exactly. - **`mc: command not found` in workspace.** Set `WORKSPACE_INSTALL_MC=true` in `.env` and `./laradock rebuild workspace`, it isn't installed by default. - **Console loads but shows no buckets you expect.** Confirm you're browsing the same MinIO instance your app writes to, if you've reset `DATA_PATH_HOST` or run multiple Laradock projects, buckets don't carry over. - **Port already in use on your host.** Change `MINIO_PORT` or `MINIO_CONSOLE_PORT` in `.env` and restart: `./laradock restart minio`. --- Need image resizing on top of your object store? See **[Thumbor](https://laradock.io/docs/services/thumbor)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # PHP-FPM Source: https://laradock.io/docs/services/php-fpm ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is PHP-FPM? [PHP-FPM](https://www.php.net/manual/en/install.fpm.php) (FastCGI Process Manager) is the process manager that runs your PHP application code and talks FastCGI to a web server. In Laradock, `php-fpm` is the container that actually executes your app, `nginx`/`apache` proxy requests to it rather than running PHP themselves. This page covers the container itself: how it's started, what it reads from `.env`, how other services depend on it, and how to switch PHP versions and install extensions and debuggers. ## Start PHP-FPM ```bash ./laradock start php-fpm ``` ```bash docker compose up -d php-fpm ``` Web servers depend on `php-fpm` to serve dynamic requests, so bring it up alongside one: ```bash ./laradock start nginx php-fpm ``` ```bash docker compose up -d nginx php-fpm ``` `php-fpm` itself `depends_on: workspace` in `compose.yml`, both containers build from the same PHP version and share build logic. ## Stop PHP-FPM ```bash ./laradock stop php-fpm ``` ```bash docker compose stop php-fpm ``` To delete the container entirely (your app code, which lives under `APP_CODE_PATH_HOST` and isn't owned by this container, is untouched): ```bash ./laradock remove php-fpm ``` ```bash docker compose rm -sf php-fpm ``` ## Configuration The PHP version is controlled by the shared `PHP_VERSION` variable in the root `.env` (default `8.4`), not by a `php-fpm`-specific variable, it's passed into the build as `LARADOCK_PHP_VERSION`. Everything else lives in `php-fpm/defaults.env` as `PHP_FPM_INSTALL_*` build-time toggles. A few default to `true`: | Variable | Default | What it does | |---|---|---| | `PHP_FPM_INSTALL_MYSQLI` | `true` | MySQLi extension. | | `PHP_FPM_INSTALL_INTL` | `true` | Internationalization extension. | | `PHP_FPM_INSTALL_IMAGEMAGICK` | `true` | ImageMagick (Imagick) extension. | | `PHP_FPM_INSTALL_OPCACHE` | `true` | Zend OPcache. | | `PHP_FPM_INSTALL_IMAGE_OPTIMIZERS` | `true` | `jpegoptim`, `optipng`, `pngquant`, `gifsicle`. | | `PHP_FPM_INSTALL_PHPREDIS` | `true` | PHP Redis extension. | | `PHP_FPM_INSTALL_DNSUTILS` | `true` | `dig`/`nslookup` and friends. | Everything else (Xdebug, pcov, phpdbg, xhprof, BCMath, PostgreSQL, MongoDB, AMQP, LDAP, SOAP, XSL, SSH2, Swoole, Phalcon, OCI8, MSSQL, ionCube, APCu, YAML, rdkafka, New Relic, and dozens more) defaults to `false` and follows the same `PHP_FPM_INSTALL_=true` + rebuild pattern: ```env PHP_FPM_INSTALL_XDEBUG=true PHP_FPM_XDEBUG_PORT=9003 ``` ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` ```bash ./laradock start php-fpm ``` ```bash docker compose up -d php-fpm ``` A few other notable variables: `PHP_FPM_PUID`/`PHP_FPM_PGID` (default `1000`/`1000`, match the `www-data` user's UID/GID to your host user), `PHP_FPM_DEFAULT_LOCALE` (default `POSIX`), and `PHP_FPM_BASE_IMAGE_TAG_PREFIX` (default `latest`, the [`laradock/php-fpm`](https://hub.docker.com/r/laradock/php-fpm/tags/) base image tag prefix). ## Change the PHP-FPM version By default the latest stable PHP version runs. PHP-FPM serves your application code. 1. In `.env`, set `PHP_VERSION` to the version you want (any from `5.6` to `8.5`): ```dotenv PHP_VERSION=8.1 ``` 2. Rebuild the image: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` > For details on the underlying base image, see the [official PHP Docker images](https://hub.docker.com/_/php/). ## Check the installed PHP version and extensions Open a terminal inside the container to see what's actually loaded, useful after a rebuild or when an extension doesn't seem to be working: ```bash ./laradock enter php-fpm ``` ```bash docker compose exec php-fpm bash ``` ```bash php -v php -m php --ini ``` `php -m` lists every compiled-in extension, `php --ini` shows which `.ini` files PHP actually loaded (useful for confirming `laravel.ini` and any extension `.ini` files are in effect). ## Tune PHP settings (memory limit, upload size, timeouts) Laradock ships two layers of PHP config for `php-fpm`, and which one to edit depends on whether you want a quick restart to pick it up or need a full rebuild: - **`php-fpm/php{PHP_VERSION}.ini`** (for example `php-fpm/php8.4.ini`) is bind-mounted straight into the container as the main `php.ini`. Edit it and restart, no rebuild needed. - **`php-fpm/laravel.ini`** is baked into the image at build time (`memory_limit`, `upload_max_filesize`, `post_max_size`, `max_execution_time`, and a few others tuned for a typical Laravel app). Edit it and you need a rebuild for the change to apply. To bump the upload size or memory limit, edit whichever file matches, then apply it: ```bash ./laradock restart php-fpm ``` ```bash docker compose restart php-fpm ``` ...or, if you edited `laravel.ini` instead: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` **Process manager limits** (how many PHP processes can run at once) live in `php-fpm/xlaravel.pool.conf`: `pm.max_children`, `pm.start_servers`, `pm.min_spare_servers`, `pm.max_spare_servers`. This file is baked into the image, so changes here need a rebuild too, same command as above. **OPcache** is enabled by default (`PHP_FPM_INSTALL_OPCACHE=true`, configured in `php-fpm/opcache.ini`) with `opcache.validate_timestamps=1`, so PHP-FPM already detects changed files on its own, you don't normally need to clear it manually after deploying new code. If you ever do want to force a clean slate (compiled bytecode is per-process and lives in memory), restarting the container clears it since every worker process restarts fresh. ## Install PHP extensions PHP extensions are toggled per container. Each PHP container lists a flag for every extension in its `defaults.env`: `php-fpm/defaults.env`, `workspace/defaults.env`, and `php-worker/defaults.env`. 1. Find the extension's flag in the relevant container's `defaults.env`, then set it to `true` in your `.env` (for example `PHP_FPM_INSTALL_GMP=true`). 2. Rebuild that container with `--no-cache`: ```bash ./laradock rebuild --no-cache {container-name} ``` ```bash docker compose build --no-cache {container-name} ``` The sections below cover the debuggers and the individual extensions Laradock ships with. ## Install Xdebug 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_XDEBUG` - `PHP_FPM_INSTALL_XDEBUG` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` To configure Xdebug with your IDE, see this [Laravel + Laradock + PhpStorm guide](https://github.com/LarryEitel/laravel-laradock-phpstorm). ## Start or stop Xdebug Once installed, Xdebug runs on startup by default. Control it in the `php-fpm` container by running these from the Laradock root: - Stop it starting by default: `./php-fpm/xdebug stop` - Start it: `./php-fpm/xdebug start` - Check status: `./php-fpm/xdebug status` > If `./php-fpm/xdebug` reports `Permission Denied`, give it execute access with `chmod`. ## Install pcov A fast code-coverage driver for PHP 7.1+. 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_PCOV` - `PHP_FPM_INSTALL_PCOV` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` For tuning tips, see the [pcov README](https://github.com/krakjoe/pcov). ## Install phpdbg The interactive PHP debugger. 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_PHPDBG` - `PHP_FPM_INSTALL_PHPDBG` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` ## Install ionCube Loader 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_IONCUBE` - `PHP_FPM_INSTALL_IONCUBE` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` The latest loaders are always downloaded from [ionCube](http://www.ioncube.com/loaders.php). ## Install the Aerospike extension 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_AEROSPIKE` - `PHP_FPM_INSTALL_AEROSPIKE` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` ## Install the Calendar extension 1. In `.env`, set `PHP_FPM_INSTALL_CALENDAR` to `true`. 2. Rebuild: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` ## Install libfaketime Libfaketime lets you control the date and time the OS reports, set via the `PHP_FPM_FAKETIME` variable. For example, `PHP_FPM_FAKETIME=-1d` moves the clock back one day. See [libfaketime](https://github.com/wolfcw/libfaketime) for the syntax. 1. In `.env`, set `PHP_FPM_INSTALL_FAKETIME` to `true`. 2. Set `PHP_FPM_FAKETIME` to your desired offset. 3. Rebuild: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` ## Install the YAML extension Parse and emit YAML from PHP. See the [PHP YAML reference](http://php.net/manual/en/ref.yaml.php). 1. In `.env`, set `PHP_FPM_INSTALL_YAML` to `true`. 2. Rebuild: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` ## Install the rdkafka extension 1. In `.env`, set `PHP_FPM_INSTALL_RDKAFKA` to `true`. 2. Rebuild: ```bash ./laradock rebuild php-fpm ``` ```bash docker compose build php-fpm ``` Composer installs that require Kafka run from the Workspace container instead, see [Install the rdkafka extension](https://laradock.io/docs/services/workspace#install-the-rdkafka-extension) on the Workspace guide. ## Install the Decimal extension The [Decimal extension](https://php-decimal.io) adds correctly-rounded, arbitrary-precision decimal arithmetic, useful for money, measurements, and anything where float rounding is unacceptable. 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_PHPDECIMAL` - `PHP_FPM_INSTALL_PHPDECIMAL` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` ## Common issues - **Enabled an extension but it's not loaded.** `PHP_FPM_INSTALL_*` flags only take effect on build: `./laradock rebuild php-fpm` then `./laradock start php-fpm`. - **502 Bad Gateway from your web server.** Confirm `php-fpm` is actually running (`docker compose ps php-fpm`) and that the web server's upstream config points at the right container/port (`php-fpm:9000` by default, container-internal, not published to the host). - **Xdebug and Blackfire both enabled, neither works.** They can't coexist in the same PHP process, the build skips the Blackfire probe when `PHP_FPM_INSTALL_XDEBUG=true`. - **File permission mismatches on Linux.** Set `PHP_FPM_PUID`/`PHP_FPM_PGID` to your host user's `id -u`/`id -g`, then rebuild. - **"PHP Fatal error: Allowed memory size exhausted" or uploads silently failing.** Bump `memory_limit`/`upload_max_filesize`/`post_max_size`, see [Tune PHP settings](#tune-php-settings-memory-limit-upload-size-timeouts) above. --- Need the container you actually work inside (Composer, Artisan, Git)? See the **[Workspace guide](https://laradock.io/docs/services/workspace)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # PHP Worker Source: https://laradock.io/docs/services/php-worker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is PHP Worker? `php-worker` is Laradock's dedicated background-processing container. It's built on `php:${PHP_VERSION}-alpine` with [Supervisor](http://supervisord.org) installed, and its Dockerfile sets Supervisor as the container's entrypoint (`ENTRYPOINT ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"]`). Supervisor keeps whatever processes you configure alive and restarts them if they crash, in practice, that means Laravel's `queue:work` (or any other long-running worker command) instead of one-off `queue:work` runs that die when a request-scoped process exits. Unlike `php-fpm`, this container never serves HTTP requests, it just runs Supervisor-managed background processes against your mounted code. ## Start PHP Worker ```bash ./laradock start php-worker ``` ```bash docker compose up -d php-worker ``` It depends on `workspace` (shares PHP version and build context) and mounts `./php-worker/supervisord.d` into `/etc/supervisord.d` inside the container, that's where you define which commands Supervisor actually runs. Your app code is mounted read/write from `APP_CODE_PATH_HOST`, there's no separate data volume for this container, it holds no state of its own. ## Stop PHP Worker ```bash ./laradock stop php-worker ``` ```bash docker compose stop php-worker ``` To delete the container entirely (your app code and Supervisor configs live on disk outside the container, so nothing is lost): ```bash ./laradock remove php-worker ``` ```bash docker compose rm -sf php-worker ``` ## Configure what it runs Add a Supervisor program config to `php-worker/supervisord.d/` (mounted, not baked into the image), for example a Laravel queue worker: ```ini [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/artisan queue:work --sleep=3 --tries=3 autostart=true autorestart=true numprocs=1 user=laradock redirect_stderr=true ``` `user=laradock` runs the process as the container's non-root user (matches `PHP_WORKER_PUID`/`PHP_WORKER_PGID`) instead of root, and `redirect_stderr=true` folds stderr into the same log stream as stdout so `docker compose logs php-worker` shows everything. Restart the container to pick up new or changed Supervisor configs: ```bash ./laradock restart php-worker ``` ```bash docker compose restart php-worker ``` ## Run more worker processes in parallel `numprocs` controls how many copies of the same program Supervisor runs side by side, this is how you scale queue throughput without adding another container. `php-worker/supervisord.d/laravel-worker.conf.example` ships with `numprocs=8` as a starting point: ```ini [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/artisan queue:work --sleep=3 --tries=3 autostart=true autorestart=true numprocs=8 user=laradock redirect_stderr=true ``` `%(process_num)02d` in `process_name` is what keeps the 8 instances uniquely named (`laravel-worker_00` through `laravel-worker_07`); the `command` itself doesn't need to change, each instance independently pulls the next available job off the queue. Restart the container after changing `numprocs` for it to take effect. ## Run the Laravel scheduler `php-worker/supervisord.d/laravel-scheduler.conf.example` is a second ready-made config, for `artisan schedule:run` instead of `queue:work`: ```ini [program:laravel-scheduler] process_name=%(program_name)s_%(process_num)02d command=/bin/sh -c "while [ true ]; do (php /var/www/artisan schedule:run --verbose --no-interaction &); sleep 60; done" autostart=true autorestart=true numprocs=1 user=laradock redirect_stderr=true ``` It loops `schedule:run` every 60 seconds, the same effect as a host cron entry, without needing cron installed anywhere. Copy either `.example` file (drop the `.example` suffix) into `php-worker/supervisord.d/` and restart the container to enable it. ## Check worker status Supervisor exposes an HTTP control interface on `127.0.0.1:9001` inside the container (see `php-worker/supervisord.conf`). From inside the container, `supervisorctl` reports what's running, restarting, or crashed: ```bash ./laradock enter php-worker supervisorctl -c /etc/supervisord.conf -s http://127.0.0.1:9001 status ``` ```bash docker compose exec php-worker bash supervisorctl -c /etc/supervisord.conf -s http://127.0.0.1:9001 status ``` Each line shows one program (or one `numprocs` instance) and its state: `RUNNING`, `STARTING`, `BACKOFF` (crash-looping), `FATAL` (gave up restarting), or `STOPPED`. ## Restart a single worker without restarting the container `docker compose restart php-worker` restarts every program Supervisor manages at once. To bounce just one, for example after deploying new code, without dropping jobs currently running in other workers, use `supervisorctl restart` with that program's name from the `status` output above: ```bash ./laradock enter php-worker supervisorctl -c /etc/supervisord.conf -s http://127.0.0.1:9001 restart laravel-worker:* ``` ```bash docker compose exec php-worker bash supervisorctl -c /etc/supervisord.conf -s http://127.0.0.1:9001 restart laravel-worker:* ``` `laravel-worker:*` restarts every `numprocs` instance of that one program group; swap in the exact name from `status` (e.g. `laravel-worker:laravel-worker_00`) to restart a single instance. ## Configuration The PHP version follows the shared `PHP_VERSION` variable in the root `.env` (same as `workspace`/`php-fpm`), passed in as `LARADOCK_PHP_VERSION`. Extension toggles live in `php-worker/defaults.env` as `PHP_WORKER_INSTALL_*` build-time flags, almost all default to `false`; the one exception: | Variable | Default | What it does | |---|---|---| | `PHP_WORKER_INSTALL_INTL` | `true` | Internationalization extension. | | `PHP_WORKER_PUID` / `PHP_WORKER_PGID` | `1000` / `1000` | UID/GID for the container's non-root `laradock` user. | Everything else, BZ2, GD, ImageMagick, GMP, GnuPG, LDAP, PostgreSQL, MongoDB, BCMath, Memcached, OCI8, MSSQL, Phalcon, APCu, SOAP, ZipArchive, MySQL client, AMQP, Ghostscript, Swoole, Taint, FFmpeg, Cassandra, Gearman, Redis, IMAP, XML-RPC, SSDB, Event, poppler-utils, GraphViz, follows the same pattern: ```env PHP_WORKER_INSTALL_REDIS=true ``` ```bash ./laradock rebuild php-worker ``` ```bash docker compose build php-worker ``` ```bash ./laradock start php-worker ``` ```bash docker compose up -d php-worker ``` ## Common issues - **Worker doesn't pick up code changes.** `artisan queue:work` caches your app in memory per worker process; Supervisor restarting the process (`autorestart=true`) handles crashes, but code changes still need an explicit restart: `./laradock restart php-worker`, or use `queue:listen` instead of `queue:work` if you want changes picked up per job (slower, more overhead). - **Added a Supervisor config but nothing runs.** Config changes in `php-worker/supervisord.d/` need a container restart to be read: `./laradock restart php-worker`. Check [Check worker status](#check-worker-status) above to confirm the program shows up and is `RUNNING`. - **Enabled an extension but it's not loaded.** `PHP_WORKER_INSTALL_*` flags only take effect on build: `./laradock rebuild php-worker` then `./laradock start php-worker`. - **A worker keeps crash-looping (`BACKOFF`/`FATAL`).** Usually a bad `command=` path or a PHP fatal error on boot. Check `./laradock logs php-worker`, Supervisor logs each managed process's stdout/stderr there by default. - **Jobs fail silently.** Check `./laradock logs php-worker`, Supervisor logs each managed process's stdout/stderr there by default. --- Need the container that serves HTTP requests? See the **[PHP-FPM guide](https://laradock.io/docs/services/php-fpm)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Selenium Source: https://laradock.io/docs/services/selenium ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Selenium? [Selenium](https://www.selenium.dev) is a browser automation framework. Laradock runs a Selenium WebDriver server in its own container so you can drive real browser tests (Laravel Dusk, Panther, or any WebDriver client) without installing a browser and driver stack on your host. ## Start Selenium ```bash ./laradock start selenium ``` ```bash docker compose up -d selenium ``` ## Stop Selenium ```bash ./laradock stop selenium ``` ```bash docker compose stop selenium ``` Selenium keeps no data between runs, so there's nothing to preserve or lose here, stopping (or removing) the container just frees the port until you start it again. ## Configuration Selenium's only Laradock-level setting lives in `selenium/defaults.env`: | Variable | Default | What it does | |---|---|---| | `SELENIUM_PORT` | `4444` | Host port the Selenium WebDriver hub is published on. | The container also mounts your host's `/dev/shm` into the container at the same path, browsers (especially Chrome) can run out of shared memory and crash without this. ## Connect a WebDriver client Open [http://localhost:4444/wd/hub](http://localhost:4444/wd/hub) to confirm the hub is up. Point your WebDriver client (Dusk, Panther, raw Selenium bindings) at that same URL. From inside another Laradock container, use `http://selenium:4444/wd/hub` instead of `localhost`. ## Watch the browser live (noVNC) The underlying image (`selenium/standalone-chrome`) runs a VNC server alongside the browser, so you can literally watch what your tests are doing instead of guessing from a stack trace. It isn't published by default in `selenium/compose.yml`, add the port mapping yourself: ```yaml services: selenium: ports: - "${SELENIUM_PORT}:4444" - "7900:7900" ``` Then restart: ```bash ./laradock restart selenium ``` ```bash docker compose restart selenium ``` Open [http://localhost:7900](http://localhost:7900) in a browser and connect, the default noVNC password is `secret`. Useful for debugging a test that fails only in CI-like headless conditions. ## Use a different browser Laradock's `selenium/Dockerfile` is pinned to `selenium/standalone-chrome`. To test against Firefox instead, point it at the equivalent upstream image: ```dockerfile FROM selenium/standalone-firefox ``` Then rebuild: ```bash ./laradock rebuild selenium ``` ```bash docker compose build selenium ``` Everything else on this page (port, `/dev/shm`, VNC) works the same regardless of which browser image you use. ## Common issues - **Browser crashes mid-test with no clear error.** This is almost always `/dev/shm` running out of space under a heavy test suite; the container already mounts the host's `/dev/shm`, if you're still hitting this, check available shared memory on your host. - **Tests hang waiting for a session.** Confirm the container actually started: `./laradock logs selenium`. A hub that never reports itself ready will leave WebDriver clients waiting indefinitely. - **App under test can't be reached by the browser.** The Selenium container needs to reach your app over the Docker network, use a container name (e.g. `nginx` or `http://workspace`) in your base test URL, not `localhost`, which inside the `selenium` container refers to itself. - **Port already in use on your host.** Change `SELENIUM_PORT` in `.env` and restart: `./laradock restart selenium`. --- Running Laravel Dusk? See the [Dusk documentation](https://laravel.com/docs/dusk) for driving it against this hub. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Thumbor Source: https://laradock.io/docs/services/thumbor ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Thumbor? [Thumbor](https://github.com/thumbor/thumbor) is an open-source smart imaging service: it crops, resizes, and flips images on demand via URL parameters, with pluggable loaders and storage backends (filesystem, Redis, MongoDB, S3-compatible). ## Start Thumbor ```bash ./laradock start thumbor ``` ```bash docker compose up -d thumbor ``` ## Stop Thumbor ```bash ./laradock stop thumbor ``` ```bash docker compose stop thumbor ``` To delete the container entirely (the cached images on disk are untouched, they live under `DATA_PATH_HOST`): ```bash ./laradock remove thumbor ``` ```bash docker compose rm -sf thumbor ``` ## Configuration Thumbor exposes nearly every native Thumbor setting as an env var in `thumbor/defaults.env`. The most commonly changed ones: | Variable | Default | What it does | |---|---|---| | `THUMBOR_PORT` | `8000` | Host port Thumbor is published on. | | `SECURITY_KEY` | `MY_SECURE_KEY` | Signing key for generated URLs. Change this before using anything beyond local dev. | | `ALLOW_UNSAFE_URL` | `True` | Allows `/unsafe/` URLs that skip signature verification. Convenient locally, disable it for anything public. | | `MAX_WIDTH` / `MAX_HEIGHT` | `0` | Maximum output dimensions (`0` = unlimited). | | `MIN_WIDTH` / `MIN_HEIGHT` | `1` | Minimum output dimensions. | | `QUALITY` | `80` | JPEG output quality (0-100). | | `LOADER` | `thumbor.loaders.http_loader` | Where Thumbor fetches source images from (HTTP by default). | | `STORAGE` | `thumbor.storages.file_storage` | Where Thumbor caches source images (`FILE_STORAGE_ROOT_PATH=/data/storage`). | | `RESULT_STORAGE` | `thumbor.result_storages.file_storage` | Where Thumbor caches generated results (`RESULT_STORAGE_FILE_STORAGE_ROOT_PATH=/data/result_storage`). | | `ENGINE` | `thumbor.engines.pil` | Image processing engine. | | `ALLOWED_SOURCES` | `[]` | Optional allow-list of source hostnames/patterns Thumbor will fetch from. | There are dozens more (Redis/MongoDB storage hosts, S3-compatible `TC_AWS_*` settings, HTTP loader timeouts and proxy settings, upload handling, Sentry error reporting), all listed in `thumbor/defaults.env` and passed straight through as environment variables in `thumbor/compose.yml`. Everything Thumbor writes to disk (file-based source/result storage, logs) lives under `${DATA_PATH_HOST}/thumbor/data` on your host, mounted into the container at `/data`. ## Apply a configuration change Env var changes in `.env` are only picked up when the container is recreated, a plain restart isn't enough. Re-run the start command after editing `.env`: ```bash ./laradock start thumbor ``` ```bash docker compose up -d thumbor ``` ## Try it out ``` http://localhost:8000/unsafe/300x300/i.imgur.com/bvjzPct.jpg ``` `/unsafe/` only works while `ALLOW_UNSAFE_URL=True`. For signed URLs, generate them with your `SECURITY_KEY` using a [Thumbor URL-signing library](https://thumbor.readthedocs.io/en/latest/libraries.html) for your language. ## Health check Thumbor ships a built-in health endpoint that returns `200 OK` with the body `WORKING` when the service is up, useful for load balancers, uptime checks, or just confirming the container is actually serving requests: ``` http://localhost:8000/healthcheck ``` ## Use Redis or MongoDB for storage By default Thumbor caches source and result images to the filesystem (`FILE_STORAGE_ROOT_PATH`/`RESULT_STORAGE_FILE_STORAGE_ROOT_PATH`). If you're already running Laradock's `redis` or `mongo` services, Thumbor's Redis/Mongo storage env vars already default to those container names (`REDIS_STORAGE_SERVER_HOST=redis`, `MONGO_STORAGE_SERVER_HOST=mongo`), so switching backends is just a `STORAGE`/`RESULT_STORAGE` change plus starting the backend service alongside Thumbor: ```env STORAGE=thumbor.storages.redis_storage RESULT_STORAGE=thumbor.result_storages.redis_storage ``` ```bash ./laradock start thumbor redis ``` Swap in `thumbor.storages.mongo_storage` / `thumbor.result_storages.mongo_storage` for MongoDB instead, and start `mongo` alongside it. Sharing a storage backend across multiple Thumbor instances (e.g. behind a load balancer) is the main reason to move off the filesystem default. ## Clear the on-disk cache Thumbor caches source images and generated results by URL under `${DATA_PATH_HOST}/thumbor/data`. If you've overwritten an image at the same source URL and need Thumbor to stop serving a stale result before `STORAGE_EXPIRATION_SECONDS`/`RESULT_STORAGE_EXPIRATION_SECONDS` naturally expires it, clear the cache directories directly: ```bash rm -rf "${DATA_PATH_HOST:-~/.laradock/data}/thumbor/data/storage" "${DATA_PATH_HOST:-~/.laradock/data}/thumbor/data/result_storage" ``` This only clears the file-based cache. If you've switched `STORAGE`/`RESULT_STORAGE` to Redis or MongoDB (see above), flush or clear that backend instead. ## Common issues - **Images never resize, just pass through.** Check `./laradock logs thumbor` for loader errors, if `LOADER` can't reach the source URL (network, DNS, or `ALLOWED_SOURCES` blocking it), Thumbor fails the request rather than silently serving the original. - **Signed URLs stop validating after changing `SECURITY_KEY`.** Any URL signed with the old key becomes invalid immediately, this is expected: re-sign URLs after rotating the key. - **Result cache never seems to update for a source image that changed.** Thumbor caches by URL, if you overwrite an image at the same source URL, cached results won't reflect the change until `STORAGE_EXPIRATION_SECONDS`/`RESULT_STORAGE_EXPIRATION_SECONDS` expire it, or you [clear the cache](#clear-the-on-disk-cache) manually. - **Config changes in `.env` don't seem to apply.** A plain `./laradock restart thumbor` doesn't re-read `.env`, [recreate the container](#apply-a-configuration-change) instead. - **Port already in use on your host.** Change `THUMBOR_PORT` in `.env` and restart: `./laradock start thumbor`. --- Need S3-compatible storage to serve source images from? See **[MinIO](https://laradock.io/docs/services/minio)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Tomcat Source: https://laradock.io/docs/services/tomcat ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Tomcat? [Apache Tomcat](https://tomcat.apache.org) is a Java Servlet container that runs Java web applications packaged as WAR files. Laradock runs it from the official `tomcat` Docker image. ## Start Tomcat ```bash ./laradock start tomcat ``` ```bash docker compose up -d tomcat ``` ## Stop Tomcat Stopping just pauses the container; your deployed WAR files and logs are untouched (they live on your host, under `DATA_PATH_HOST`): ```bash ./laradock stop tomcat ``` ```bash docker compose stop tomcat ``` To delete the container entirely (your webapps and logs on disk are still untouched): ```bash ./laradock remove tomcat ``` ```bash docker compose rm -sf tomcat ``` ## Configuration Settings live in `tomcat/defaults.env` and can be overridden in your own `.env`: | Variable | Default | What it does | |---|---|---| | `TOMCAT_VERSION` | `9.0` | Image tag from the [official `tomcat` Docker Hub page](https://hub.docker.com/_/tomcat). | | `TOMCAT_HOST_HTTP_PORT` | `8080` | Host port Tomcat is published on (container always listens on `8080` internally). | Tomcat runs from a prebuilt image (no local Dockerfile), so after changing `.env` a restart is enough, no rebuild step exists for this service: ```bash ./laradock restart tomcat ``` ```bash docker compose restart tomcat ``` ## Deploy a WAR file Drop a `.war` file into `DATA_PATH_HOST/tomcat/webapps`, it's mounted straight into Tomcat's own `webapps` directory, so Tomcat picks it up and auto-deploys it without a rebuild: ```bash cp your-app.war "${DATA_PATH_HOST}/tomcat/webapps/" ``` Open [http://localhost:8080](http://localhost:8080) to reach the Tomcat welcome page, or `http://localhost:8080/your-app` once your WAR has deployed. Logs are written to `DATA_PATH_HOST/tomcat/logs`, also mounted from the host. ## Undeploy a WAR file Tomcat auto-deploys by unpacking the WAR into a matching folder next to it. To remove an app, delete both the archive and its exploded folder, then Tomcat drops it on the next check: ```bash rm -rf "${DATA_PATH_HOST}/tomcat/webapps/your-app.war" "${DATA_PATH_HOST}/tomcat/webapps/your-app" ``` To see everything currently deployed: ```bash ls "${DATA_PATH_HOST}/tomcat/webapps" ``` ## Tune JVM memory (heap size) Tomcat's startup script (`catalina.sh`, which the official image runs) reads the `JAVA_OPTS` environment variable for JVM flags like heap size. Laradock's `tomcat/compose.yml` doesn't set one by default, add it yourself under the `tomcat` service: ```yaml services: tomcat: environment: - JAVA_OPTS=-Xms256m -Xmx1024m ``` Then apply it: ```bash ./laradock restart tomcat ``` ```bash docker compose up -d tomcat ``` ## View logs Tomcat's own deployment/application logs (`catalina.out`, per-app logs) are written to `DATA_PATH_HOST/tomcat/logs` on your host, read them directly or tail them with your usual tools. For the container's own stdout/stderr (startup messages, JVM errors before logging is set up): ```bash ./laradock logs tomcat ``` ```bash docker compose logs --tail=100 tomcat ``` ## Common issues - **WAR file doesn't deploy.** Check `DATA_PATH_HOST/tomcat/logs` for deployment errors, malformed WAR files or Java errors surface there, not in `./laradock logs tomcat`. - **Changing `TOMCAT_VERSION` doesn't take effect.** Tomcat runs from a prebuilt image (no local Dockerfile to rebuild), so a plain restart after changing `.env` is enough: `./laradock restart tomcat`. - **Port already in use on your host.** Change `TOMCAT_HOST_HTTP_PORT` in `.env` and restart: `./laradock restart tomcat`. - **Undeploying a WAR doesn't remove it.** Delete both the `.war` file and its exploded folder from `DATA_PATH_HOST/tomcat/webapps`, deleting only one of the two leaves Tomcat confused about the app's state. --- New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Workspace Source: https://laradock.io/docs/services/workspace ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is the Workspace container? `workspace` is Laradock's general-purpose development shell, the container you `exec` into to run Composer, Artisan, Git, Node/npm, and most other CLI work against your mounted project code. It's built from the [`laradock/workspace`](https://hub.docker.com/r/laradock/workspace/tags/) base image (tagged by PHP version) and runs as a non-root `laradock` user matched to your host UID/GID, so files it creates aren't owned by root. Unlike `php-fpm`, it's not what actually serves your app to a browser, `nginx`/`apache` talk to `php-fpm` for that. `workspace` is where you sit and type commands. ## Enter the Workspace The fastest path in is the dedicated shortcut, it starts `workspace` for you if it isn't running yet (equivalent to the [Start the Workspace](#start-the-workspace) command below), then drops you in as the non-root `laradock` user: ```bash ./laradock workspace ``` ```bash docker compose exec -u laradock workspace bash ``` You land in `/var/www` (your project, mounted from `APP_CODE_PATH_HOST`) as the `laradock` user. Pass `--root` (CLI only: `./laradock workspace --root`) to land as `root` instead, useful for one-off `apt-get` installs. `ws` and `shell` also work as shorthands for `./laradock workspace`. ## Start the Workspace If you'd rather start it explicitly, without entering a shell, for example alongside other services: ```bash ./laradock start workspace ``` ```bash docker compose up -d workspace ``` Name any other services alongside it to start them together, for example `./laradock start nginx mysql workspace`. ## Stop the Workspace ```bash ./laradock stop workspace ``` ```bash docker compose stop workspace ``` ## What's installed by default A handful of `WORKSPACE_INSTALL_*` / `WORKSPACE_*` flags in `workspace/defaults.env` default to `true` (everything else defaults to `false`): | Variable | Default | What it does | |---|---|---| | `WORKSPACE_INSTALL_NODE` | `true` | Node.js via NVM (`WORKSPACE_NODE_VERSION=node` tracks latest). | | `WORKSPACE_INSTALL_YARN` | `true` | Yarn package manager. | | `WORKSPACE_INSTALL_NPM_GULP` | `true` | Gulp CLI, global npm install. | | `WORKSPACE_INSTALL_NPM_VUE_CLI` | `true` | Vue CLI, global npm install. | | `WORKSPACE_INSTALL_PHPREDIS` | `true` | PHP Redis extension (for CLI scripts, Artisan, etc.). | | `WORKSPACE_INSTALL_AST` | `true` | PHP AST extension. | | `WORKSPACE_INSTALL_MEMCACHED` | `true` | PHP Memcached extension. | | `WORKSPACE_INSTALL_DNSUTILS` | `true` | `dig`/`nslookup` and friends. | | `WORKSPACE_INSTALL_JDK` | `true` | Java Development Kit. | | `WORKSPACE_COMPOSER_GLOBAL_INSTALL` | `true` | Runs `composer global install` at build time. | | `WORKSPACE_COMPOSER_VERSION` | `2` | Composer major version (`1`, `2`, `2.2`, or a specific version string). | ## Pick your tools with the CLI The wizard asks about workspace tools directly, so you don't have to know a flag name to find a tool. Step 8 of `./laradock setup` is a searchable, grouped picker over every tool below, with what you already have pre-ticked: ```bash ./laradock setup ``` ``` ---------------------------------------------------------------------- Step 8 of 10 Workspace tools ---------------------------------------------------------------------- The workspace is your dev shell: the container you run php, composer, artisan, npm and git inside (./laradock workspace). These are the tools baked into it. Debug & testing [ ] xdebug [x] pcov Node & frontend [x] node ... type to filter Β· arrows move Β· space toggles on/off Β· enter when done ``` Type to filter (`xde` finds `xdebug`), space to toggle, enter to accept. Only the tools you actually change are written to your `.env`, so it stays a short diff of your choices rather than a copy of all ~87 flags. When you change something, the CLI reminds you to rebuild. It's safe to re-run `./laradock setup` any time to add or remove tools later; your current answers are pre-filled. ## The `WORKSPACE_INSTALL_*` toggle pattern If you'd rather not use the wizard, every tool is just an on/off flag in `workspace/defaults.env`: `WORKSPACE_INSTALL_=false`. Flip one to `true` in your `.env`, then rebuild: ```env WORKSPACE_INSTALL_XDEBUG=true WORKSPACE_INSTALL_DRUSH=true WORKSPACE_INSTALL_WP_CLI=true ``` ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` Then restart it to pick up the new build: ```bash ./laradock restart workspace ``` ```bash docker compose up -d workspace ``` To turn one back off, either untick it in `./laradock setup`, or: ```bash ./laradock unset WORKSPACE_INSTALL_XDEBUG # back to the shipped default ./laradock rebuild workspace ``` Removing a tool rebuilds the image without it. Your code and database are untouched: the workspace holds no data of its own, only tools. ## Every tool you can install The complete list, grouped the same way the `./laradock setup` picker groups them. **On** = installed unless you turn it off. Names in the first column are what you type in the picker; the flag is what you'd set by hand. ### Debug & testing | Tool | Flag | Default | What it does | |---|---|---|---| | `xdebug` | `WORKSPACE_INSTALL_XDEBUG` | off | Step debugger and profiler. See the [Xdebug + IDE guide](https://laradock.io/docs/xdebug-ide). | | `pcov` | `WORKSPACE_INSTALL_PCOV` | off | Fast code-coverage driver for PHPUnit (much quicker than Xdebug's). | | `phpdbg` | `WORKSPACE_INSTALL_PHPDBG` | off | PHP's built-in interactive debugger, also usable for coverage. | | `dusk-deps` | `WORKSPACE_INSTALL_DUSK_DEPS` | off | Chrome and the libraries Laravel Dusk needs for browser tests (amd64 only). | | `taint` | `WORKSPACE_INSTALL_TAINT` | off | Static analysis extension that flags possible XSS in strings. | ### Node & frontend | Tool | Flag | Default | What it does | |---|---|---|---| | `node` | `WORKSPACE_INSTALL_NODE` | **on** | Node.js via NVM. Version set by `WORKSPACE_NODE_VERSION`. | | `yarn` | `WORKSPACE_INSTALL_YARN` | **on** | Yarn package manager. | | `pnpm` | `WORKSPACE_INSTALL_PNPM` | off | pnpm package manager. | | `npm-gulp` | `WORKSPACE_INSTALL_NPM_GULP` | **on** | Gulp task runner CLI, installed globally. | | `npm-vue-cli` | `WORKSPACE_INSTALL_NPM_VUE_CLI` | **on** | Vue CLI, installed globally. | | `npm-angular-cli` | `WORKSPACE_INSTALL_NPM_ANGULAR_CLI` | off | Angular CLI, installed globally. | | `npm-bower` | `WORKSPACE_INSTALL_NPM_BOWER` | off | Bower, the legacy frontend package manager. | | `npm-check-updates-cli` | `WORKSPACE_INSTALL_NPM_CHECK_UPDATES_CLI` | off | `ncu`, checks your `package.json` for newer versions. | ### Database clients & drivers | Tool | Flag | Default | What it does | |---|---|---|---| | `mysql-client` | `WORKSPACE_INSTALL_MYSQL_CLIENT` | off | The `mysql` command, for a SQL shell or `mysqldump` from the workspace. | | `pg-client` | `WORKSPACE_INSTALL_PG_CLIENT` | off | The `psql` command and Postgres client tools. | | `mongo` | `WORKSPACE_INSTALL_MONGO` | off | PHP MongoDB driver. | | `mssql` | `WORKSPACE_INSTALL_MSSQL` | off | PHP SQL Server driver (`sqlsrv`/`pdo_sqlsrv`). | | `oci8` | `WORKSPACE_INSTALL_OCI8` | off | PHP Oracle driver. Needs the Instant Client files. | | `cassandra` | `WORKSPACE_INSTALL_CASSANDRA` | off | PHP Cassandra driver. | | `aerospike` | `WORKSPACE_INSTALL_AEROSPIKE` | off | PHP Aerospike driver. | | `ssdb` | `WORKSPACE_INSTALL_SSDB` | off | PHP SSDB client. | | `rdkafka` | `WORKSPACE_INSTALL_RDKAFKA` | off | PHP Kafka client. See [the section below](#install-the-rdkafka-extension). | | `zookeeper` | `WORKSPACE_INSTALL_ZOOKEEPER` | off | PHP ZooKeeper client. | ### PHP extensions | Tool | Flag | Default | What it does | |---|---|---|---| | `phpredis` | `WORKSPACE_INSTALL_PHPREDIS` | **on** | Redis extension, so Artisan and CLI scripts can talk to Redis. | | `memcached` | `WORKSPACE_INSTALL_MEMCACHED` | **on** | Memcached extension. | | `apcu` | `WORKSPACE_INSTALL_APCU` | off | In-memory user cache (APCu). | | `amqp` | `WORKSPACE_INSTALL_AMQP` | off | AMQP extension, for RabbitMQ. | | `gearman` | `WORKSPACE_INSTALL_GEARMAN` | off | Gearman job-queue client. | | `event` | `WORKSPACE_INSTALL_EVENT` | off | libevent bindings for async PHP. | | `swoole` | `WORKSPACE_INSTALL_SWOOLE` | off | Coroutine/async runtime used by Octane, Hyperf. | | `soap` | `WORKSPACE_INSTALL_SOAP` | off | SOAP client/server. | | `gnupg` | `WORKSPACE_INSTALL_GNUPG` | off | GnuPG encryption bindings. | | `gmp` | `WORKSPACE_INSTALL_GMP` | off | Arbitrary-precision maths. | | `bz2` | `WORKSPACE_INSTALL_BZ2` | off | bzip2 compression. | | `imap` | `WORKSPACE_INSTALL_IMAP` | off | IMAP mailbox access. | | `ldap` | `WORKSPACE_INSTALL_LDAP` | off | LDAP / Active Directory auth. | | `mailparse` | `WORKSPACE_INSTALL_MAILPARSE` | off | Parse raw email messages. | | `phpdecimal` | `WORKSPACE_INSTALL_PHPDECIMAL` | off | Correctly-rounded decimal maths, for money. | | `ssh2` | `WORKSPACE_INSTALL_SSH2` | off | SSH/SFTP from PHP. | | `xmlrpc` | `WORKSPACE_INSTALL_XMLRPC` | off | XML-RPC client/server. | | `xsl` | `WORKSPACE_INSTALL_XSL` | off | XSLT transforms. | | `yaml` | `WORKSPACE_INSTALL_YAML` | off | Fast YAML parsing. | | `zmq` | `WORKSPACE_INSTALL_ZMQ` | off | ZeroMQ messaging. | | `trader` | `WORKSPACE_INSTALL_TRADER` | off | Technical-analysis functions. | | `xlswriter` | `WORKSPACE_INSTALL_XLSWRITER` | off | Write large Excel files quickly. | | `v8js` | `WORKSPACE_INSTALL_V8JS` | off | Run JavaScript from PHP via V8. | | `phalcon` | `WORKSPACE_INSTALL_PHALCON` | off | The Phalcon framework extension. | | `ast` | `WORKSPACE_INSTALL_AST` | **on** | Exposes PHP's syntax tree. Needed by Phan and other static analysers. | | `ioncube` | `WORKSPACE_INSTALL_IONCUBE` | off | ionCube loader for encoded PHP. Not available on PHP 8.0 or 8.4+. | ### Framework CLIs | Tool | Flag | Default | What it does | |---|---|---|---| | `laravel-installer` | `WORKSPACE_INSTALL_LARAVEL_INSTALLER` | off | The `laravel new` command. | | `laravel-envoy` | `WORKSPACE_INSTALL_LARAVEL_ENVOY` | off | Envoy task runner for remote deploys. | | `symfony` | `WORKSPACE_INSTALL_SYMFONY` | off | The Symfony CLI. | | `deployer` | `WORKSPACE_INSTALL_DEPLOYER` | off | Deployer, the PHP deployment tool. | | `drush` | `WORKSPACE_INSTALL_DRUSH` | off | Drupal's command line. | | `drupal-console` | `WORKSPACE_INSTALL_DRUPAL_CONSOLE` | off | Drupal Console. | | `wp-cli` | `WORKSPACE_INSTALL_WP_CLI` | off | The `wp` command, for WordPress. | | `prestissimo` | `WORKSPACE_INSTALL_PRESTISSIMO` | off | Parallel downloads for Composer 1. Pointless on Composer 2. | ### Media & documents | Tool | Flag | Default | What it does | |---|---|---|---| | `imagemagick` | `WORKSPACE_INSTALL_IMAGEMAGICK` | off | Image manipulation, plus the PHP `imagick` extension. | | `libpng` | `WORKSPACE_INSTALL_LIBPNG` | off | PNG libraries some image tools need. | | `ffmpeg` | `WORKSPACE_INSTALL_FFMPEG` | off | Audio/video transcoding. | | `audiowaveform` | `WORKSPACE_INSTALL_AUDIOWAVEFORM` | off | BBC waveform data generator. | | `image-optimizers` | `WORKSPACE_INSTALL_IMAGE_OPTIMIZERS` | off | jpegoptim, optipng, pngquant, svgo and friends. | | `wkhtmltopdf` | `WORKSPACE_INSTALL_WKHTMLTOPDF` | off | Render HTML to PDF. | | `poppler-utils` | `WORKSPACE_INSTALL_POPPLER_UTILS` | off | `pdftotext` and other PDF tools. | | `graphviz` | `WORKSPACE_INSTALL_GRAPHVIZ` | off | Render `.dot` graphs to images. | ### Shell & tools | Tool | Flag | Default | What it does | |---|---|---|---| | `git-prompt` | `WORKSPACE_INSTALL_GIT_PROMPT` | off | Show the current branch in your shell prompt. | | `powerline` | `WORKSPACE_INSTALL_POWERLINE` | off | Powerline status line for the prompt. | | `mc` | `WORKSPACE_INSTALL_MC` | off | Midnight Commander, a terminal file manager. | | `lnav` | `WORKSPACE_INSTALL_LNAV` | off | Log file navigator. | | `linuxbrew` | `WORKSPACE_INSTALL_LINUXBREW` | off | Homebrew for Linux, for anything not listed here. | | `gnu-parallel` | `WORKSPACE_INSTALL_GNU_PARALLEL` | off | Run shell jobs in parallel. | | `fswatch` | `WORKSPACE_INSTALL_FSWATCH` | off | Watch files and react to changes. | | `inotify` | `WORKSPACE_INSTALL_INOTIFY` | off | PHP inotify bindings for file watching. | | `ping` | `WORKSPACE_INSTALL_PING` | off | The `ping` command. | | `dnsutils` | `WORKSPACE_INSTALL_DNSUTILS` | **on** | `dig`, `nslookup`, for debugging container DNS. | | `sshpass` | `WORKSPACE_INSTALL_SSHPASS` | off | Non-interactive SSH passwords, for scripts. | | `subversion` | `WORKSPACE_INSTALL_SUBVERSION` | off | The `svn` client. | | `smb` | `WORKSPACE_INSTALL_SMB` | off | SMB/CIFS client, for Windows shares. | | `supervisor` | `WORKSPACE_INSTALL_SUPERVISOR` | off | Keep queue workers and daemons running. | ### DevOps | Tool | Flag | Default | What it does | |---|---|---|---| | `docker-client` | `WORKSPACE_INSTALL_DOCKER_CLIENT` | off | The `docker` command inside the workspace. See [Docker-in-Docker](#docker-cli-inside-the-workspace-docker-in-docker). | | `terraform` | `WORKSPACE_INSTALL_TERRAFORM` | off | The Terraform CLI. | | `github-cli` | `WORKSPACE_INSTALL_GITHUB_CLI` | off | The `gh` command. | | `protoc` | `WORKSPACE_INSTALL_PROTOC` | off | Protocol Buffers compiler. | | `workspace-ssh` | `WORKSPACE_INSTALL_WORKSPACE_SSH` | off | Run an SSH server in the workspace. See [SSH into the Workspace](#ssh-into-the-workspace). | ### Other languages | Tool | Flag | Default | What it does | |---|---|---|---| | `python` | `WORKSPACE_INSTALL_PYTHON` | off | Python 2 and pip. | | `python3` | `WORKSPACE_INSTALL_PYTHON3` | off | Python 3 and pip3. | | `jdk` | `WORKSPACE_INSTALL_JDK` | **on** | Java Development Kit. Only needed for tools that run on Java. | See the sections below for setup instructions on individual tools, and the **[PHP-FPM guide](https://laradock.io/docs/services/php-fpm)** for extension-specific install/config guides (Xdebug, pcov, phpdbg, YAML, rdkafka, ionCube, etc.) that apply to `workspace` as well as `php-fpm`. ## Published ports `workspace/compose.yml` exposes several dev-server ports on the host, all overridable in `.env`: | Variable | Default | Used for | |---|---|---| | `WORKSPACE_SSH_PORT` | `2222` | SSH into the container (if `WORKSPACE_INSTALL_WORKSPACE_SSH=true`). | | `WORKSPACE_BROWSERSYNC_HOST_PORT` | `3000` | Browsersync. | | `WORKSPACE_BROWSERSYNC_UI_HOST_PORT` | `3001` | Browsersync UI. | | `WORKSPACE_VUE_CLI_SERVE_HOST_PORT` | `8080` | `vue-cli-service serve`. | | `WORKSPACE_VUE_CLI_UI_HOST_PORT` | `8001` | Vue CLI UI. | | `WORKSPACE_ANGULAR_CLI_SERVE_HOST_PORT` | `4200` | Angular CLI dev server. | | `WORKSPACE_VITE_PORT` | `5173` | Vite dev server. | ## User and permissions `WORKSPACE_PUID`/`WORKSPACE_PGID` (default `1000`/`1000`) set the UID/GID of the `laradock` user inside the container. Match these to your host user if you're on Linux and hitting file-ownership mismatches on files created inside the container. ## Change the PHP-CLI version The PHP-CLI lives in the Workspace container and is used only for Artisan and Composer, it does not serve your application code (that's PHP-FPM's job), so changing it is usually optional. 1. In `.env`, set `PHP_VERSION` to the version you want: ```dotenv PHP_VERSION=8.1 ``` 2. Rebuild the Workspace: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ## Install the rdkafka extension Needed for `composer install` when your dependencies require Kafka. 1. In `.env`, set `WORKSPACE_INSTALL_RDKAFKA` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` To install rdkafka for the PHP-FPM container instead (the one that actually serves your app), see [Install the rdkafka extension](https://laradock.io/docs/services/php-fpm#install-the-rdkafka-extension) on the PHP-FPM guide. ## Install the AST extension AST exposes the abstract syntax tree generated by PHP 7+. It's required by tools such as [Phan](https://github.com/phan/phan), a static analyzer. `WORKSPACE_INSTALL_AST` defaults to `true`, so it's already installed unless you've turned it off. 1. In `.env`, set `WORKSPACE_INSTALL_AST` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` > To pin a specific version, set `WORKSPACE_AST_VERSION` before rebuilding. ## Node.js & NVM 1. In `.env`, set `WORKSPACE_INSTALL_NODE` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` > A `.npmrc` is included in the `workspace` folder and is copied into the root and laradock users' home directories on build, in case you need global npm config. ## Package managers ### pnpm pnpm stores a single copy of each package version on disk and hard-links it into each project's `node_modules`, saving large amounts of space and speeding up installs. More on the [pnpm motivation](https://pnpm.js.org/en/motivation). 1. In `.env`, set both `WORKSPACE_INSTALL_NODE` and `WORKSPACE_INSTALL_PNPM` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### Yarn 1. In `.env`, set both `WORKSPACE_INSTALL_NODE` and `WORKSPACE_INSTALL_YARN` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### npm-check-updates [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) upgrades your `package.json` dependencies to the latest versions. 1. In `.env`, make sure `WORKSPACE_INSTALL_NODE` is `true`. 2. Set `WORKSPACE_INSTALL_NPM_CHECK_UPDATES_CLI` to `true`. 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ## Frontend build tool CLIs ### Gulp 1. In `.env`, set `WORKSPACE_INSTALL_NPM_GULP` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### Bower > Legacy. Bower is deprecated, prefer npm, Yarn, or pnpm for new projects. 1. In `.env`, set `WORKSPACE_INSTALL_NPM_BOWER` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### Vue CLI 1. In `.env`, set `WORKSPACE_INSTALL_NPM_VUE_CLI` to `true`. 2. Optionally change the ports: `WORKSPACE_VUE_CLI_SERVE_HOST_PORT` (default `8080`) and `WORKSPACE_VUE_CLI_UI_HOST_PORT` (default `8001`). 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` Run `vue serve` or `vue ui` from the Workspace, then browse to the matching port. ### Angular CLI 1. In `.env`, set `WORKSPACE_INSTALL_NPM_ANGULAR_CLI` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ## Composer extras ### Global Composer install Install your global Composer requirements at build time so they're available in the container afterward. 1. In `.env`, set `WORKSPACE_COMPOSER_GLOBAL_INSTALL` to `true`. 2. Add your dependencies to `workspace/composer.json`. 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### Prestissimo > Legacy. [Prestissimo](https://github.com/hirak/prestissimo) parallelized downloads for **Composer 1 only** and is abandoned. Composer 2 (Laradock's default) already downloads in parallel, so you almost certainly don't need this. 1. Enable Global Composer install (steps 1-2 above). 2. Add `"hirak/prestissimo": "^0.3"` to `workspace/composer.json`. 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ## Deployment & task runners ### Deployer > A deployment tool for PHP. 1. In `.env`, set `WORKSPACE_INSTALL_DEPLOYER` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` See the [Deployer documentation](https://deployer.org/docs/). ### Laravel Envoy > A task runner. 1. In `.env`, set `WORKSPACE_INSTALL_LARAVEL_ENVOY` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` See the [Laravel Envoy documentation](https://laravel.com/docs/envoy). ## System utilities ### Linuxbrew [Linuxbrew](http://linuxbrew.sh) is the Linux port of Homebrew. 1. In `.env`, set `WORKSPACE_INSTALL_LINUXBREW` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### Supervisor [Supervisor](http://supervisord.org/) monitors and controls long-running processes on UNIX-like systems. 1. In `.env`, set both `WORKSPACE_INSTALL_SUPERVISOR` and `WORKSPACE_INSTALL_PYTHON` to `true`. 2. Create a worker config in `php-worker/supervisord.d/` by copying `laravel-worker.conf.example`. 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### GNU Parallel [GNU Parallel](https://www.gnu.org/software/parallel/parallel_tutorial.html) runs multiple processes concurrently from the command line. 1. In `.env`, set `WORKSPACE_INSTALL_GNU_PARALLEL` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ### dnsutils 1. In `.env`, set both flags to `true`: - `WORKSPACE_INSTALL_DNSUTILS` - `PHP_FPM_INSTALL_DNSUTILS` 2. Rebuild: ```bash ./laradock rebuild workspace php-fpm ``` ```bash docker compose build workspace php-fpm ``` ## Media & document tools ### FFmpeg 1. In `.env`, set `WORKSPACE_INSTALL_FFMPEG` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` :::warning If you queue conversions, also install FFmpeg in the `php-worker` and `php-fpm` containers (same flag pattern), otherwise the `php-ffmpeg` binary errors out. ::: ### BBC audiowaveform [audiowaveform](https://github.com/bbc/audiowaveform) generates waveform data from MP3, WAV, FLAC, or Ogg Vorbis files, for rendering visual waveforms. 1. In `.env`, set `WORKSPACE_INSTALL_AUDIOWAVEFORM` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` :::warning If you queue processing, also install it in the `php-worker`, `laravel-horizon`, and `php-fpm` containers (same flag pattern), otherwise the `audiowaveform` binary errors out. ::: ### wkhtmltopdf [wkhtmltopdf](https://wkhtmltopdf.org/) renders a PDF from HTML. 1. In `.env`, set `WORKSPACE_INSTALL_WKHTMLTOPDF` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` :::warning Also install it in the `php-fpm` container (same flag pattern), otherwise the `wkhtmltopdf` binary errors out. ::: ### poppler-utils & antiword [poppler-utils](https://packages.debian.org/sid/poppler-utils) is a set of PDF command-line tools (info, text/image extraction, format conversion, signature verification, and more). It's commonly paired with `antiword`, so Laradock installs both together when the flag is set. 1. In `.env`, set the flag to `true` for each container you need it in: `WORKSPACE_INSTALL_POPPLER_UTILS`, `PHP_FPM_INSTALL_POPPLER_UTILS`, `PHP_WORKER_INSTALL_POPPLER_UTILS`, `LARAVEL_HORIZON_INSTALL_POPPLER_UTILS`. 2. Rebuild the affected containers: ```bash ./laradock rebuild workspace php-fpm php-worker laravel-horizon ``` ```bash docker compose build workspace php-fpm php-worker laravel-horizon ``` ### Graphviz [Graphviz](https://graphviz.org/) renders graphs from text descriptions. Enable it in whichever container needs it: | Container | Flag | Rebuild | | --------- | ---- | ------- | | Workspace | `WORKSPACE_INSTALL_GRAPHVIZ` | `./laradock rebuild workspace` | | PHP-FPM (most common) | `PHP_FPM_INSTALL_GRAPHVIZ` | `./laradock rebuild php-fpm` | | PHP-Worker | `PHP_WORKER_INSTALL_GRAPHVIZ` | `./laradock rebuild php-worker` | Set the flag to `true`, then rebuild. ## GitHub Copilot CLI > Requires GitHub Copilot access. 1. In `.env`, set `WORKSPACE_INSTALL_GITHUB_CLI` to `true`. 2. Rebuild the Workspace: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` 3. Enter the Workspace: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` (The CLI shortcut starts `workspace` for you first if it isn't already running; with plain Docker Compose, run `docker compose up -d workspace` first if needed.) 4. Authenticate, then install the Copilot extension: ```bash gh auth login gh extension install github/gh-copilot ``` ## Shell & terminal ### Oh My Zsh [Oh My Zsh](https://ohmyz.sh/) manages your [Zsh](https://en.wikipedia.org/wiki/Z_shell) configuration. Laradock wires it up with the [Laravel autocomplete plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/laravel). 1. In `.env`, set `SHELL_OH_MY_ZSH` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` 3. Use it: enter the Workspace (`./laradock workspace`, or `docker compose exec --user=laradock workspace bash`), then run `zsh`. > Configure it by editing `/home/laradock/.zshrc` in the running container. **Optional plugins:** - **Autosuggestions**: set `SHELL_OH_MY_ZSH_AUTOSUGESTIONS` to `true`, then rebuild. Suggests commands as you type, from history and completions ([zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)). - **Bash aliases**: set `SHELL_OH_MY_ZSH_ALIASES` to `true`, then rebuild, to load Laradock's `aliases.sh` into Zsh. ### Git Bash prompt A bash prompt showing the current branch, diff with remote, and counts of staged/changed files. 1. In `.env`, set `WORKSPACE_INSTALL_GIT_PROMPT` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` > Customize it by editing `workspace/gitprompt.sh` and rebuilding. See the [bash-git-prompt repo](https://github.com/magicmonty/bash-git-prompt). ### Terminal aliases On startup, Laradock copies `workspace/aliases.sh` into the container and sources it from `~/.bashrc`. Edit that file to add your own aliases or function macros. ### Powerline 1. In `.env`, set both `WORKSPACE_INSTALL_POWERLINE` and `WORKSPACE_INSTALL_PYTHON` to `true` (Powerline requires Python). 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` ## Run a one-off command without entering the shell For a single command (a CI-style `composer install`, an Artisan call from a script, etc.) you don't need an interactive session at all: ```bash docker compose exec workspace composer install docker compose exec -u laradock workspace php artisan migrate ``` There's no dedicated `./laradock` shortcut for this (only for opening an interactive shell), plain `docker compose exec` is already the simplest form. ## SSH into the Workspace Useful for pointing an IDE's remote interpreter (PhpStorm, VS Code Remote-SSH) or a deploy tool at the container over SSH instead of Docker's own exec. 1. In `.env`, set `WORKSPACE_INSTALL_WORKSPACE_SSH` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` 3. Connect to `localhost` on `WORKSPACE_SSH_PORT` (`2222` by default) as `root`, using the bundled `workspace/insecure_id_rsa` key: ```bash ssh -p 2222 -i workspace/insecure_id_rsa root@localhost ``` That key is called "insecure" for a reason, it ships in the repo and is the same for every Laradock install. Fine for a purely local dev container reachable only from your own machine; if the port is ever exposed beyond `localhost` (a shared dev server, a cloud sandbox), replace `workspace/insecure_id_rsa`/`.pub` with your own key pair before rebuilding, or don't enable SSH access at all and use `./laradock workspace`/`docker compose exec` instead. ## Docker CLI inside the Workspace (Docker-in-Docker) `workspace` can run `docker`/`docker compose` commands of its own, wired to a sibling `docker-in-docker` container (`docker:29-dind`) rather than your host's Docker socket. This is what lets tools like Testcontainers or Sail-style build scripts work from inside the Workspace. 1. In `.env`, set `WORKSPACE_INSTALL_DOCKER_CLIENT` to `true`. 2. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` `DOCKER_HOST`, `DOCKER_TLS_VERIFY`, and `DOCKER_CERT_PATH` are already set on the container's environment (see `workspace/compose.yml`), so once you're inside (`./laradock workspace`), `docker ps`/`docker build`/`docker compose ...` just work against the `docker-in-docker` sibling, completely isolated from your host's Docker. ## Private Composer packages (auth.json) If `composer install` needs credentials for a private registry (private Packagist, a private Satis, Magento's `repo.magento.com`, etc.): 1. Set `WORKSPACE_COMPOSER_AUTH_JSON` to `true` in `.env`. 2. Put your real credentials in `workspace/auth.json` (Composer's [standard `auth.json` format](https://getcomposer.org/doc/articles/http-basic-authentication.md)), the file already exists as a placeholder in that folder. 3. Rebuild: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` `workspace/auth.json` holds real credentials once you fill it in, don't commit it to your app's repo. ## Common issues - **A tool you enabled isn't there.** `WORKSPACE_INSTALL_*` flags only take effect on build, not on a plain restart: `./laradock rebuild workspace` then `./laradock start workspace`. - **Files created in the container are owned by the wrong user on your host.** Set `WORKSPACE_PUID`/`WORKSPACE_PGID` to match your host user's `id -u`/`id -g`, then rebuild. - **Composer/npm installs are painfully slow.** Set `WORKSPACE_COMPOSER_REPO_PACKAGIST` or `WORKSPACE_NPM_REGISTRY` to a closer mirror, or `CHANGE_SOURCE=true` if you're behind the Great Firewall (switches apt sources to a Tsinghua mirror). - **Xdebug and Blackfire both enabled, neither works right.** They can't coexist in the same PHP process, the build skips the Blackfire probe entirely when `WORKSPACE_INSTALL_XDEBUG=true`. --- Need the container that actually runs your PHP app? See the **[PHP-FPM guide](https://laradock.io/docs/services/php-fpm)**. New to Laradock? Start at **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Apache Source: https://laradock.io/docs/services/apache2 ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Apache? [Apache HTTP Server](https://httpd.apache.org) is one of the most widely used web servers, known for `.htaccess`-driven per-directory config and broad module support. Laradock runs it as an alternative to Nginx, proxying PHP requests to `php-fpm`. ## Start Apache ```bash ./laradock start apache2 ``` ```bash docker compose up -d apache2 ``` Apache's `compose.yml` declares `depends_on: php-fpm`, so Compose starts it automatically. Add whatever else your app needs, for example: ```bash ./laradock start apache2 mysql workspace ``` ```bash docker compose up -d apache2 mysql workspace ``` ## Stop Apache ```bash ./laradock stop apache2 ``` ```bash docker compose stop apache2 ``` ## Configuration All settings live in `apache2/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `APACHE_HOST_HTTP_PORT` | `80` | Host-side port mapped to container port 80. | | `APACHE_HOST_HTTPS_PORT` | `443` | Host-side port mapped to container port 443. | | `APACHE_HOST_LOG_PATH` | `./logs/apache2` | Host folder mounted to `/var/log/apache2`. | | `APACHE_SITES_PATH` | `./apache2/sites` | Host folder mounted to `/etc/apache2/sites-available`. | | `APACHE_PHP_UPSTREAM_CONTAINER` | `php-fpm` | Container name Apache proxies PHP requests to (build arg). | | `APACHE_PHP_UPSTREAM_PORT` | `9000` | Port on the upstream PHP container (build arg). | | `APACHE_PHP_UPSTREAM_TIMEOUT` | `60` | Proxy timeout (seconds) to the upstream PHP container (build arg). | | `APACHE_DOCUMENT_ROOT` | `/var/www/` | Document root baked into the image at build time (build arg). | | `APACHE_SSL_PATH` | `./apache2/ssl/` | Host folder mounted to `/etc/apache2/ssl`, for your certificates. | | `APACHE_INSTALL_HTTP2` | `false` | Set `true` to enable the HTTP/2 module at build time. | | `APACHE_FOR_MAC_M1` | `false` | Set `true` when building on Apple Silicon (build arg). | ## Add a site config Files in `apache2/sites/` become available VirtualHosts. There's `default.apache.conf` (serves `APACHE_DOCUMENT_ROOT` on `laradock.test`), `default.apache.ssl.example` (SSL version), and `sample.conf.example` for a project with its own document root: ```bash cp apache2/sites/sample.conf.example apache2/sites/myapp.conf ``` Edit `ServerName` and `DocumentRoot`, then restart: ```bash ./laradock restart apache2 ``` ```bash docker compose restart apache2 ``` ```apacheconf ServerName sample.test DocumentRoot /var/www/sample/public/ Options Indexes FollowSymLinks AllowOverride All Require all granted ``` ## Test a config change before restarting A typo in a VirtualHost file can take the whole server down on restart. Check syntax first, inside the running container: ```bash ./laradock enter apache2 apache2ctl configtest ``` ```bash docker compose exec apache2 bash apache2ctl configtest ``` `Syntax OK` means it's safe to restart. Anything else names the file and line to fix. ## Enable SSL Copy `apache2/sites/default.apache.ssl.example` alongside your site config, point it at your certificate files under the folder set by `APACHE_SSL_PATH` (`./apache2/ssl/` by default), and restart the container. ## Enable HTTP/2 ```env APACHE_INSTALL_HTTP2=true ``` ```bash ./laradock rebuild apache2 ``` ```bash docker compose build apache2 ``` ```bash ./laradock start apache2 ``` ```bash docker compose up -d apache2 ``` ## Change the exposed port ```env APACHE_HOST_HTTP_PORT=8080 APACHE_HOST_HTTPS_PORT=8443 ``` ```bash ./laradock start apache2 ``` ```bash docker compose up -d apache2 ``` ## View logs Apache writes `error.log` and `access.log` per VirtualHost (see `ErrorLog`/`CustomLog` in the shipped site configs) to `/var/log/apache2` inside the container, which is bind-mounted to `APACHE_HOST_LOG_PATH` (`./logs/apache2` by default) on your host. Read them straight from your host with any tool (`tail -f`, an editor, etc.), no container access needed: ```bash tail -f logs/apache2/error.log ``` For the container's own stdout/stderr (startup messages, not per-request traffic): ```bash ./laradock logs apache2 ``` ```bash docker compose logs --tail=100 apache2 ``` ## Common issues - **502/503 from Apache.** Confirm `php-fpm` is running and that `APACHE_PHP_UPSTREAM_CONTAINER`/`APACHE_PHP_UPSTREAM_PORT` match its real name and port; also check `APACHE_PHP_UPSTREAM_TIMEOUT` if long-running requests are being cut off. - **New site file has no effect.** VirtualHosts in `apache2/sites/` are read on container start, run `./laradock restart apache2` after adding or editing a file. - **`.htaccess` rules ignored.** Confirm the VirtualHost has `AllowOverride All` in its `` block, as shown in the shipped examples. - **Building on Apple Silicon fails or behaves oddly.** Set `APACHE_FOR_MAC_M1=true` and rebuild. - **Port already in use on your host.** Another web server (or another Laradock project) is already bound to `80`/`443`. Change `APACHE_HOST_HTTP_PORT`/`APACHE_HOST_HTTPS_PORT` and restart. - **Restart succeeded but the site still 500s.** Check `logs/apache2/error.log` on your host (or `./laradock logs apache2` for startup-time errors) for the actual PHP or Apache error before guessing further. --- Need a different web server? See **[Nginx](https://laradock.io/docs/services/nginx)**, **[Caddy](https://laradock.io/docs/services/caddy)**, or **[OpenResty](https://laradock.io/docs/services/openresty)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Caddy Source: https://laradock.io/docs/services/caddy ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Caddy? [Caddy](https://caddyserver.com) is a modern web server best known for automatic HTTPS: it can provision and renew TLS certificates with zero manual config. Laradock runs it as an alternative to Nginx or Apache, driven by a single `Caddyfile`. ## Start Caddy ```bash ./laradock start caddy ``` ```bash docker compose up -d caddy ``` Caddy's `compose.yml` declares `depends_on: php-fpm`, so Compose starts `php-fpm` automatically. Add whatever else your app needs, for example `./laradock start caddy mysql workspace`. ## Stop Caddy Stopping just pauses the container; **your Caddyfile and TLS state are untouched**: ```bash ./laradock stop caddy ``` ```bash docker compose stop caddy ``` To delete the container entirely (the `Caddyfile` and TLS state on disk are still untouched): ```bash ./laradock remove caddy ``` ```bash docker compose rm -sf caddy ``` ## Configuration All settings live in `caddy/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `CADDY_HOST_HTTP_PORT` | `80` | Host-side port mapped to container port 80. | | `CADDY_HOST_HTTPS_PORT` | `443` | Host-side port mapped to container port 443. | | `CADDY_HOST_LOG_PATH` | `./logs/caddy` | Host folder mounted to `/var/log/caddy`. | | `CADDY_CONFIG_PATH` | `./caddy/caddy` | Host folder mounted to `/etc/caddy`, containing the `Caddyfile`. | Caddy's automatic-HTTPS state (certificates, OCSP staples, account keys, normally kept under `/root/.caddy` inside the container) is stored under `DATA_PATH_HOST`. Unlike most other services, Caddy's `compose.yml` mounts `DATA_PATH_HOST` itself straight to `/root/.caddy`, not a `DATA_PATH_HOST/caddy` subfolder, so that path is shared with whatever other services' data also lives directly under `DATA_PATH_HOST`. Keep that in mind before deleting anything there, see [Common issues](#common-issues). ## The Caddyfile The shipped `caddy/caddy/Caddyfile` serves the app with automatic HTTPS out of the box: ```caddyfile laradock.test { root * /var/www/public php_fastcgi php-fpm:9000 file_server encode zstd gzip tls internal } ``` `php_fastcgi php-fpm:9000` proxies PHP requests straight to the `php-fpm` container, and `tls internal` tells Caddy to mint a locally trusted certificate rather than reaching out to Let's Encrypt, which is what you want for local development. `CADDY_CONFIG_PATH` (`./caddy/caddy` by default) is bind-mounted straight to `/etc/caddy` inside the container, the same host folder the `Dockerfile` also bakes the `Caddyfile` from at build time. Because the bind mount wins at runtime, editing `caddy/caddy/Caddyfile` on your host takes effect without rebuilding the image, you only need to apply it: ```bash ./laradock restart caddy ``` ```bash docker compose restart caddy ``` ## Validate and reload without downtime Restarting the container drops active connections for a moment. Caddy's own CLI can validate a config and hot-reload it in place instead, keeping existing connections and certificates alive. Open a terminal inside the container: ```bash ./laradock enter caddy ``` ```bash docker compose exec caddy bash ``` Then, inside the container: ```bash caddy validate --config /etc/caddy/Caddyfile caddy reload --config /etc/caddy/Caddyfile ``` `caddy validate` catches syntax errors before you commit to a change, and `caddy reload` tells the already-running Caddy process (over its local admin API) to swap in the new config live, no dropped connections and no container restart. ## Use a real domain with public HTTPS For a publicly reachable domain, replace `tls internal` with your email (or remove the `tls` line entirely) so Caddy requests a certificate from Let's Encrypt instead: ```caddyfile yourdomain.com { root * /var/www/public php_fastcgi php-fpm:9000 file_server } ``` Your domain needs to resolve to the host running Laradock, and `CADDY_HOST_HTTP_PORT`/`CADDY_HOST_HTTPS_PORT` need to be reachable on `80`/`443` for the ACME challenge to succeed. ## Change the exposed port ```env CADDY_HOST_HTTP_PORT=8080 CADDY_HOST_HTTPS_PORT=8443 ``` ```bash ./laradock start caddy ``` ```bash docker compose up -d caddy ``` ## Common issues - **Browser doesn't trust the certificate.** `tls internal` issues a certificate from Caddy's local CA, not a public one. Trust that CA locally, or use a public domain with Let's Encrypt as described above. - **502 from Caddy.** Confirm `php-fpm` is running and reachable at `php-fpm:9000`, the address hardcoded in the shipped `Caddyfile`. Check `./laradock logs caddy` for the underlying error. - **Changes to the Caddyfile don't take effect.** Edits to `caddy/caddy/Caddyfile` apply on the next `./laradock restart caddy` (or a live `caddy reload`, see above), no rebuild needed since the config folder is bind-mounted, not just baked into the image. - **Port already in use on your host.** Another web server (or another Laradock project) is already bound to `80`/`443`. Change `CADDY_HOST_HTTP_PORT`/`CADDY_HOST_HTTPS_PORT` and restart. - **Deleting `DATA_PATH_HOST` wipes more than Caddy.** Caddy's TLS state is mounted directly from `DATA_PATH_HOST` (not a `DATA_PATH_HOST/caddy` subfolder), so it's the same top-level folder other services may also store data in. Don't `rm -rf` it to "reset" Caddy, back up anything else under `DATA_PATH_HOST` first, or just delete Caddy's own state files inside it if you can identify them (`autosave.json`, the `certificates/`, `locks/`, and `ocsp/` folders it creates). --- Need a different web server? See **[Nginx](https://laradock.io/docs/services/nginx)** or **[Apache](https://laradock.io/docs/services/apache2)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # FrankenPHP Source: https://laradock.io/docs/services/frankenphp ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is FrankenPHP? [FrankenPHP](https://frankenphp.dev) is a modern PHP application server built on Caddy, an alternative to the classic Nginx + PHP-FPM split. It serves your app directly (no separate web server container needed) with automatic HTTPS, HTTP/3, and a worker mode, and is the recommended runtime for [Laravel Octane](https://laravel.com/docs/octane). ## Start FrankenPHP ```bash ./laradock start frankenphp ``` ```bash docker compose up -d frankenphp ``` FrankenPHP is self-contained: it doesn't declare a dependency on `php-fpm` or Nginx, it serves your app directly. ## Stop FrankenPHP Stopping just pauses the container, your app code on disk is untouched: ```bash ./laradock stop frankenphp ``` ```bash docker compose stop frankenphp ``` To delete the container entirely (your app code and the image are untouched): ```bash ./laradock remove frankenphp ``` ```bash docker compose rm -sf frankenphp ``` ## Restart FrankenPHP Useful after changing `.env` values like the ports below: ```bash ./laradock restart frankenphp ``` ```bash docker compose restart frankenphp ``` ## Configuration All settings live in `frankenphp/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `FRANKENPHP_VERSION` | `1-php8` | FrankenPHP image tag (build arg). | | `FRANKENPHP_HTTP_PORT` | `8000` | Host-side port mapped to container port 80. | | `FRANKENPHP_HTTPS_PORT` | `8443` | Host-side port mapped to container port 443. | Your app is mounted at `/app` inside the container (Laravel docroot `/app/public`), via `${APP_CODE_PATH_HOST}:/app`. ## Access your app ``` https://localhost:8443 ``` HTTP on `FRANKENPHP_HTTP_PORT` (`8000` by default) auto-redirects to HTTPS. ## Add PHP extensions Edit `frankenphp/Dockerfile` and add to its `install-php-extensions` call, then rebuild: ```bash ./laradock rebuild frankenphp ``` ```bash docker compose build frankenphp ``` Then start it again with the rebuilt image: ```bash ./laradock start frankenphp ``` ```bash docker compose up -d frankenphp ``` ## View logs ```bash ./laradock logs frankenphp ``` ```bash docker compose logs --tail=100 frankenphp ``` Caddy's access/error log lines and any PHP errors your app writes to stderr both show up here, useful for diagnosing a blank page or a certificate problem without opening a shell. ## Open a shell inside the container ```bash ./laradock enter frankenphp ``` ```bash docker compose exec frankenphp bash ``` Since FrankenPHP *is* your app's PHP runtime (there's no separate `php-fpm` container in this stack), this is also where you'd run one-off `php` or `php artisan` commands if you want them to execute under the exact same PHP/extension set that serves requests, instead of the `workspace` container. ## Use with Laravel Octane worker mode For Octane's worker mode (keeping your app booted in memory between requests instead of bootstrapping per request), follow the [Octane + FrankenPHP docs](https://laravel.com/docs/octane#frankenphp). The container already serves your mounted app; worker mode is configured on the Laravel side. ## Common issues - **Browser doesn't trust the HTTPS certificate.** FrankenPHP, like Caddy, issues a locally trusted certificate automatically for development; trust it locally or configure a real domain for production use. - **HTTP/3 doesn't seem to work.** HTTP/3 runs over QUIC, which needs a **UDP** port published, but `frankenphp/compose.yml` only maps `FRANKENPHP_HTTPS_PORT` as TCP. Browsers still work fine over HTTP/1.1 or HTTP/2, but to actually get HTTP/3 locally you'd need to add a matching `"${FRANKENPHP_HTTPS_PORT}:443/udp"` line to the `ports:` list yourself. - **Extension changes don't apply.** PHP extensions are installed at build time via the `Dockerfile`, so after editing it you need `./laradock rebuild frankenphp`, not just a restart. - **Port already in use on your host.** Another service is already bound to `8000`/`8443`. Change `FRANKENPHP_HTTP_PORT`/`FRANKENPHP_HTTPS_PORT` and restart with `./laradock restart frankenphp`. - **App not found / blank page.** Confirm your Laravel docroot is `public/` under the mounted app folder, FrankenPHP expects `/app/public` inside the container. --- Looking for the classic Nginx + PHP-FPM setup instead? See **[Nginx](https://laradock.io/docs/services/nginx)**. Want another Octane-compatible runtime? See **[RoadRunner](https://laradock.io/docs/services/roadrunner)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # HAProxy Source: https://laradock.io/docs/services/haproxy ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is HAProxy? [HAProxy](https://www.haproxy.org) is a high-performance TCP/HTTP load balancer widely used to distribute traffic across multiple backend servers. In Laradock it runs as a self-configuring load balancer container, built from the `dockercloud/haproxy` image, which watches the Docker socket and automatically balances traffic across whatever containers it's linked to. ## Start HAProxy ```bash ./laradock start haproxy ``` ```bash docker compose up -d haproxy ``` `haproxy/compose.yml` links to `proxy` and `proxy2`, the two containers created by the **[Varnish](https://laradock.io/docs/services/varnish)** service. Start those first (or alongside it) if you're load-balancing across them: ```bash ./laradock start proxy proxy2 haproxy ``` ```bash docker compose up -d proxy proxy2 haproxy ``` ## Stop HAProxy ```bash ./laradock stop haproxy ``` ```bash docker compose stop haproxy ``` ## Configuration The only setting is in `haproxy/defaults.env`, overridable by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `HAPROXY_HOST_HTTP_PORT` | `8085` | Host-side port mapped to container port 8085. | There's no site or backend config file to edit directly: the `dockercloud/haproxy` base image builds its balancing rules automatically from the containers it's linked to (`proxy` and `proxy2` in the shipped `compose.yml`), by watching `/var/run/docker.sock`. ## How it balances traffic HAProxy mounts the Docker socket (`/var/run/docker.sock`) so it can detect its linked containers' ports at startup and load-balance across them without a static config file. To balance across different containers than the defaults, edit the `links:` list in `haproxy/compose.yml`. ## Balance across different containers Edit the `links:` list in `haproxy/compose.yml` to point at whatever containers you want balanced instead of (or alongside) `proxy`/`proxy2`, then recreate the container so it picks up the new links: ```bash ./laradock start haproxy ``` ```bash docker compose up -d haproxy ``` A `restart` isn't enough here, `links:` is read when the container is created, not on every restart. Recreating (`up -d`, which is what `start` does) is required. ## View the built-in stats page The `dockercloud/haproxy` base image ships with a live stats dashboard, enabled by default on container port `1936` with the credentials `stats` / `stats`. It isn't published to your host by default, add a port mapping in `haproxy/compose.yml` to reach it: ```yaml ports: - "${HAPROXY_HOST_HTTP_PORT}:8085" - "1936:1936" ``` Recreate the container after editing, then open `http://localhost:1936` in your browser and log in with `stats` / `stats`. You can change the port and credentials the image listens on via its own `STATS_PORT` and `STATS_AUTH` environment variables if you add them to `haproxy/compose.yml`. ## Change the exposed port ```env HAPROXY_HOST_HTTP_PORT=8090 ``` ```bash ./laradock start haproxy ``` ```bash docker compose up -d haproxy ``` ## Common issues - **HAProxy starts but has nothing to balance.** It only load-balances containers listed under `links:` in `haproxy/compose.yml` (`proxy` and `proxy2` by default). Make sure those containers are actually running: `./laradock start proxy proxy2`. - **Port already in use on your host.** Another service is already bound to `8085`. Change `HAPROXY_HOST_HTTP_PORT` and restart with `./laradock start haproxy`. - **Changes to `links:` don't seem to apply.** `dockercloud/haproxy` reads its linked containers when the container is created, not on every restart, so after editing `links:` you need to recreate it with `./laradock start haproxy`, not just `./laradock restart haproxy`. - **Can't reach the stats page.** It's not published to your host out of the box, see [View the built-in stats page](#view-the-built-in-stats-page) above. --- Looking for the containers HAProxy balances by default? See **[Varnish](https://laradock.io/docs/services/varnish)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Nginx Source: https://laradock.io/docs/services/nginx ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Nginx? [Nginx](https://nginx.org) is a fast, low-memory HTTP server and reverse proxy, the default web server in Laradock. It terminates HTTP/HTTPS requests and forwards PHP requests to `php-fpm` over FastCGI. ## Start Nginx ```bash ./laradock start nginx ``` ```bash docker compose up -d nginx ``` Nginx's `compose.yml` declares `depends_on: php-fpm`, so Compose starts `php-fpm` automatically. You'll still want a database and any other services your app needs, for example: ```bash ./laradock start nginx mysql workspace ``` ```bash docker compose up -d nginx mysql workspace ``` ## Stop Nginx Stopping just pauses the container: ```bash ./laradock stop nginx ``` ```bash docker compose stop nginx ``` To delete the container entirely (your site configs, SSL certs, and logs on disk are untouched, they live under `NGINX_SITES_PATH`, `NGINX_SSL_PATH`, and `NGINX_HOST_LOG_PATH`): ```bash ./laradock remove nginx ``` ```bash docker compose rm -sf nginx ``` ## Configuration All settings live in `nginx/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `NGINX_HOST_HTTP_PORT` | `80` | Host-side port mapped to container port 80. | | `NGINX_HOST_HTTPS_PORT` | `443` | Host-side port mapped to container port 443. | | `NGINX_HOST_LOG_PATH` | `./logs/nginx/` | Host folder mounted to `/var/log/nginx` inside the container. | | `NGINX_SITES_PATH` | `./nginx/sites/` | Host folder mounted to `/etc/nginx/sites-available`, one file per site. | | `NGINX_PHP_UPSTREAM_CONTAINER` | `php-fpm` | Container name Nginx proxies PHP requests to (build arg). | | `NGINX_PHP_UPSTREAM_PORT` | `9000` | Port on the upstream PHP container (build arg). | | `NGINX_SSL_PATH` | `./nginx/ssl/` | Host folder mounted to `/etc/nginx/ssl`, for your certificates. | The container also publishes `${VARNISH_BACKEND_PORT}:81`, the port Varnish uses to talk back to Nginx when you run it behind Varnish as a cache. ## Add a site config Every file in `nginx/sites/` is loaded automatically. There's a `default.conf` that serves the app root on `localhost`, plus several `*.conf.example` templates for common frameworks (`laravel.conf.example`, `symfony.conf.example`, `node.conf.example`, `confluence.conf.example`, `laravel_varnish.conf.example`). To add a site: ```bash cp nginx/sites/laravel.conf.example nginx/sites/laravel.conf ``` Edit `server_name` and `root` to match your app, then restart: ```bash ./laradock restart nginx ``` ```bash docker compose restart nginx ``` The `laravel.conf.example` template already routes `.php` requests to `fastcgi_pass php-upstream;`, which resolves to `NGINX_PHP_UPSTREAM_CONTAINER:NGINX_PHP_UPSTREAM_PORT`, and denies access to `.ht*` files. ## Test your config before reloading A typo in a site file can take Nginx down entirely. Validate the config **before** restarting, so a bad file fails loudly instead of crashing the running container: ```bash ./laradock exec nginx nginx -t ``` ```bash docker compose exec nginx nginx -t ``` `nginx -t` parses every file under `/etc/nginx/sites-available` (your `nginx/sites/*.conf`) and reports the exact file and line of any syntax error, without touching the running process. Only restart once it prints `syntax is ok` / `test is successful`. ## Enable SSL Laradock generates a self-signed certificate automatically on first boot (`nginx/startup.sh`), so `NGINX_SSL_PATH` (`./nginx/ssl/` by default) already has a working `default.crt`/`default.key` pair you can use for local HTTPS testing right away. To use it (or your own certificate placed in the same folder), uncomment the SSL lines in your site config: ```conf listen 443 ssl; listen [::]:443 ssl ipv6only=on; ssl_certificate /etc/nginx/ssl/default.crt; ssl_certificate_key /etc/nginx/ssl/default.key; ``` [Test the config](#test-your-config-before-reloading), then restart the container. ## Increase the upload size Laravel/PHP file uploads larger than **20M** get rejected by Nginx itself with `413 Request Entity Too Large` before the request ever reaches PHP, since `nginx/nginx.conf` ships with: ```conf client_max_body_size 20M; ``` Raise (or lower) it in `nginx/nginx.conf`, then rebuild, since that file is baked into the image at build time (not a mounted volume): ```bash ./laradock rebuild nginx ./laradock start nginx ``` ```bash docker compose build nginx docker compose up -d nginx ``` Also raise your PHP-side limits (`upload_max_filesize`, `post_max_size` in `php-fpm`) and, if you're behind Varnish or another proxy in front of Nginx, its body-size limit too, all three have to agree or the smallest one wins. ## View logs The main Nginx process logs to the container's stdout/stderr (`access_log /dev/stdout` and `error_log /dev/stderr` in `nginx/nginx.conf`), so the fastest way to see what's happening is: ```bash ./laradock logs nginx ``` ```bash docker compose logs --tail=100 nginx ``` Site configs can also log to their own files instead, `laravel.conf.example` does this with `error_log /var/log/nginx/laravel_error.log;` and `access_log /var/log/nginx/laravel_access.log;`. Those land on your host under `NGINX_HOST_LOG_PATH` (`./logs/nginx/` by default), and `nginx/logrotate/nginx` rotates them daily and keeps 32 days. ## Change the exposed port ```env NGINX_HOST_HTTP_PORT=8080 NGINX_HOST_HTTPS_PORT=8443 ``` ```bash ./laradock start nginx ``` ```bash docker compose up -d nginx ``` Port mappings are set when the container is created, so this needs `up -d` (recreates the container) rather than `restart`. ## Common issues - **502 Bad Gateway.** Nginx can't reach PHP-FPM. Confirm `php-fpm` is running (`docker compose ps php-fpm`) and that `NGINX_PHP_UPSTREAM_CONTAINER`/`NGINX_PHP_UPSTREAM_PORT` match its actual name and port. - **New site file has no effect.** Config in `nginx/sites/` is picked up on container start, run `./laradock restart nginx` after adding or editing a file, and [test it first](#test-your-config-before-reloading) if you're not sure it's valid. - **413 Request Entity Too Large.** Your upload exceeds `client_max_body_size` (`20M` by default). See [Increase the upload size](#increase-the-upload-size). - **Port already in use on your host.** Another web server (or another Laradock project) is already bound to `80`/`443`. Change `NGINX_HOST_HTTP_PORT`/`NGINX_HOST_HTTPS_PORT` and restart. - **Domain doesn't resolve.** Add it to `/etc/hosts` pointing at `127.0.0.1`, and set `server_name` in the site config to match. --- Need a different web server? See **[Apache](https://laradock.io/docs/services/apache2)**, **[Caddy](https://laradock.io/docs/services/caddy)**, or **[OpenResty](https://laradock.io/docs/services/openresty)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # OpenResty Source: https://laradock.io/docs/services/openresty ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is OpenResty? [OpenResty](https://openresty.org) is Nginx bundled with LuaJIT and a set of Lua modules, letting you script request handling (auth, routing, rate limiting, API gateways) directly inside the web server instead of only through Nginx's native directives. Everything about its config format is Nginx-compatible: site files are plain Nginx server blocks, with Lua available where you need it. ## Start OpenResty ```bash ./laradock start openresty ``` ```bash docker compose up -d openresty ``` OpenResty's `compose.yml` declares `depends_on: php-fpm`, so Compose starts it automatically. Name any other services alongside it to start them together, for example `./laradock start openresty mysql workspace`. ## Stop OpenResty ```bash ./laradock stop openresty ``` ```bash docker compose stop openresty ``` ## Configuration All settings live in `openresty/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `OPENRESTY_HOST_HTTP_PORT` | `80` | Host-side port mapped to container port 80. | | `OPENRESTY_HOST_HTTPS_PORT` | `443` | Host-side port mapped to container port 443. | | `OPENRESTY_HOST_LOG_PATH` | `./logs/openresty/` | Host folder mounted to `/var/log/nginx`. | | `OPENRESTY_SITES_PATH` | `./openresty/sites/` | Host folder mounted to `/etc/nginx/sites-available`, one file per site. | | `OPENRESTY_PHP_UPSTREAM_CONTAINER` | `php-fpm` | Container name OpenResty proxies PHP requests to (build arg). | | `OPENRESTY_PHP_UPSTREAM_PORT` | `9000` | Port on the upstream PHP container (build arg). | | `OPENRESTY_SSL_PATH` | `./openresty/ssl/` | Host folder mounted to `/etc/nginx/ssl`, for your certificates. | The container also publishes `${VARNISH_BACKEND_PORT}:81`, the port Varnish uses to talk back when you run OpenResty behind Varnish as a cache, same as the Nginx service. ## Add a site config Every file in `openresty/sites/` is loaded automatically, using the same server-block syntax as plain Nginx. There's a `default.conf` plus framework templates (`laravel.conf.example`, `symfony.conf.example`, `node.conf.example`, `confluence.conf.example`, `laravel_varnish.conf.example`): ```bash cp openresty/sites/laravel.conf.example openresty/sites/laravel.conf ``` Edit `server_name` and `root` to match your app, then restart: ```bash ./laradock restart openresty ``` ```bash docker compose restart openresty ``` `fastcgi_pass php-upstream;` in these templates resolves to `OPENRESTY_PHP_UPSTREAM_CONTAINER:OPENRESTY_PHP_UPSTREAM_PORT`. ## Test your config before reloading Nginx-style config errors otherwise only surface as a failed reload or a container stuck in a restart loop. Check syntax **before** restarting, from inside the container: ```bash ./laradock enter openresty nginx -t ``` ```bash docker compose exec openresty bash nginx -t ``` `nginx -t` reports `syntax is ok` / `test is successful`, or points at the exact file and line that's broken, without touching the running server. OpenResty ships the same `nginx` binary under the hood, so this works exactly like plain Nginx. ## Script requests with Lua This is what sets OpenResty apart from plain Nginx: any directive that accepts a `*_by_lua_block` can run Lua inline, no separate app server needed. A minimal example in a site config: ```nginx location /healthz { default_type text/plain; content_by_lua_block { ngx.say("ok") } } ``` Common hooks: `access_by_lua_block` (auth/rate limiting before the request is proxied), `content_by_lua_block` (generate the response yourself, skip PHP-FPM entirely), `header_filter_by_lua_block` (rewrite response headers). None of the bundled `openresty/sites/*.conf.example` templates use Lua, they're plain Nginx server blocks, add `*_by_lua_block` directives to your own site file where you need scripting. ## Enable SSL Uncomment the SSL lines in your site config (`listen 443 ssl;`, `ssl_certificate`, `ssl_certificate_key`), and place your certificate and key in the folder pointed to by `OPENRESTY_SSL_PATH` (`./openresty/ssl/` by default), then restart the container. If you don't provide your own certificate, the container generates a self-signed one on first start (`default.key`/`default.crt` in `OPENRESTY_SSL_PATH`), good enough for local HTTPS testing but browsers will flag it as untrusted, replace it with a real certificate (or a [mkcert](https://github.com/FiloSottile/mkcert) local CA) for anything beyond a quick check. ## Change the exposed port ```env OPENRESTY_HOST_HTTP_PORT=8080 OPENRESTY_HOST_HTTPS_PORT=8443 ``` ```bash ./laradock restart openresty ``` ```bash docker compose restart openresty ``` ## Logs Access and error logs are written to `OPENRESTY_HOST_LOG_PATH` on your host (`./logs/openresty/` by default), already rotated daily and kept for 32 days by the bundled `logrotate` config, so you don't need to prune them yourself. Tail them live: ```bash ./laradock logs openresty ``` ```bash docker compose logs --tail=100 openresty ``` That's the container's stdout/stderr (startup and crond output). For the actual Nginx access/error logs, read the files directly from `OPENRESTY_HOST_LOG_PATH` on your host, or `tail -f` them from inside the container after `./laradock enter openresty`. ## Common issues - **502 Bad Gateway.** OpenResty can't reach PHP-FPM. Confirm `php-fpm` is running and that `OPENRESTY_PHP_UPSTREAM_CONTAINER`/`OPENRESTY_PHP_UPSTREAM_PORT` match its real name and port. - **New site file has no effect.** Config in `openresty/sites/` is read on container start, run `./laradock restart openresty` after adding or editing a file. - **Container won't start after a config edit.** Run `nginx -t` (see [Test your config before reloading](#test-your-config-before-reloading)) to find the broken directive before restarting again. - **Not sure whether to reach for Lua or plain server-block config.** If you don't need scripted request handling, the vanilla **[Nginx](https://laradock.io/docs/services/nginx)** service uses the same site config format and is a lighter-weight choice. - **Port already in use on your host.** Another web server (or another Laradock project) is already bound to `80`/`443`. Change `OPENRESTY_HOST_HTTP_PORT`/`OPENRESTY_HOST_HTTPS_PORT` and restart. --- Need a different web server? See **[Nginx](https://laradock.io/docs/services/nginx)**, **[Apache](https://laradock.io/docs/services/apache2)**, or **[Caddy](https://laradock.io/docs/services/caddy)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # RoadRunner Source: https://laradock.io/docs/services/roadrunner ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is RoadRunner? [RoadRunner](https://roadrunner.dev) is a high-performance PHP application server written in Go, an alternative to PHP-FPM for keeping long-running PHP worker processes alive between requests instead of bootstrapping your app from scratch every time. It's a supported driver for [Laravel Octane](https://laravel.com/docs/octane). The Laradock image pulls the official `rr` binary and layers it on a PHP-CLI Alpine image with the `sockets` and `opcache` extensions installed, then serves your mounted app via its `.rr.yaml` config (`CMD ["rr", "serve"]`). ## Start RoadRunner ```bash ./laradock start roadrunner ``` ```bash docker compose up -d roadrunner ``` RoadRunner is self-contained: it doesn't declare a dependency on `php-fpm` or a web server, it serves your app directly via the `rr` binary. ## Stop RoadRunner ```bash ./laradock stop roadrunner ``` ```bash docker compose stop roadrunner ``` ## Configuration All settings live in `roadrunner/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `ROADRUNNER_VERSION` | `2025.1.15` | Version of the official RoadRunner image the `rr` binary is pulled from (build arg). | | `ROADRUNNER_HTTP_PORT` | `8090` | Host-side port mapped to container port 8080. | The container also builds against `LARADOCK_PHP_VERSION` (Laradock's shared `PHP_VERSION`) and `CHANGE_SOURCE`, and adds an `extra_hosts` entry for `dockerhost` pointing at `DOCKER_HOST_IP`. ## Set up Octane with RoadRunner 1. In your Laravel app, install Octane with the RoadRunner driver: ```bash composer require laravel/octane spiral/roadrunner-cli php artisan octane:install --server=roadrunner ``` This generates a `.rr.yaml` file. Set its HTTP address to `0.0.0.0:8080` so it's reachable from outside the container. 2. Start the container: ```bash ./laradock start roadrunner ``` ```bash docker compose up -d roadrunner ``` 3. Your app is served on the host at `ROADRUNNER_HTTP_PORT` (`8090` by default), mapped to container port `8080`. ## Change the exposed port Set the new host-side port in your `.env`: ```env ROADRUNNER_HTTP_PORT=8095 ``` Then recreate the container so the new port mapping takes effect: ```bash ./laradock start roadrunner ``` ```bash docker compose up -d roadrunner ``` ## Reload workers after a code change RoadRunner boots your app once per worker and keeps it in memory between requests (that's the entire point of Octane workers), so unlike PHP-FPM it does **not** pick up code changes on the next request automatically. Reset the worker pool from inside the container instead of restarting it: ```bash ./laradock enter roadrunner ``` ```bash rr reset ``` ```bash docker compose exec roadrunner bash ``` ```bash rr reset ``` This restarts the worker pool in place (no dropped connections, no container restart), so freshly deployed code is picked up on the next request. It needs an `rpc: listen:` block in your `.rr.yaml` (added automatically by `php artisan octane:install --server=roadrunner`); without it `rr reset` has nothing to connect to. ## Common issues - **Container starts but nothing responds.** `.rr.yaml` needs its HTTP address set to `0.0.0.0:8080`, not `127.0.0.1:8080`, otherwise it only listens inside its own network namespace. - **`.rr.yaml` not found.** It's generated by `php artisan octane:install --server=roadrunner` inside your Laravel app; run that first, and confirm your app code is mounted correctly via `APP_CODE_PATH_HOST`. - **Code changes don't show up.** Workers keep your app booted in memory; [reset the worker pool](#reload-workers-after-a-code-change) after deploying, don't expect a plain page refresh to pick up new code. - **Extension-related errors.** The image only installs `sockets` and `opcache` by default; additional extensions need to be added to `roadrunner/Dockerfile` and the image rebuilt with `./laradock rebuild roadrunner`. - **Port already in use on your host.** Another service is already bound to `8090`. Change `ROADRUNNER_HTTP_PORT` and restart with `./laradock start roadrunner`. --- Want another Octane-compatible runtime? See **[FrankenPHP](https://laradock.io/docs/services/frankenphp)**. Looking for the classic Nginx + PHP-FPM setup instead? See **[Nginx](https://laradock.io/docs/services/nginx)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Traefik Source: https://laradock.io/docs/services/traefik ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Traefik? [Traefik](https://traefik.io) is a reverse proxy and load balancer that discovers backend containers automatically and terminates TLS for them. Instead of publishing a web server's ports directly to your host, you route through Traefik using Docker labels, and it handles certificate issuance via Let's Encrypt. ## Start Traefik ```bash ./laradock start traefik ``` ```bash docker compose up -d traefik ``` Traefik doesn't declare a `depends_on` on `php-fpm`, it routes to whatever containers you've labeled, so start your web server and other services alongside it as needed, for example `./laradock start traefik nginx`. ## Stop Traefik Stopping just pauses the container; the ACME account and issued certificates in `traefik/data` are untouched: ```bash ./laradock stop traefik ``` ```bash docker compose stop traefik ``` To delete the container entirely (the data on disk is still untouched, it lives under `traefik/data`): ```bash ./laradock remove traefik ``` ```bash docker compose rm -sf traefik ``` ## Configuration All settings live in `traefik/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `TRAEFIK_HOST_HTTP_PORT` | `80` | Host-side HTTP entrypoint port. | | `TRAEFIK_HOST_HTTPS_PORT` | `443` | Host-side HTTPS entrypoint port. | | `TRAEFIK_DASHBOARD_PORT` | `8888` | Host-side port for the Traefik dashboard. | | `TRAEFIK_DASHBOARD_USER` | `admin:$2y$10$...` (bcrypt hash) | Basic-auth credentials for the dashboard, default `admin` / `admin`. | | `ACME_DOMAIN` | `example.org` | Domain Traefik requests a Let's Encrypt certificate for. | | `ACME_EMAIL` | `email@example.org` | Email used for the Let's Encrypt account. | ## Route a service through Traefik Traefik routes by label, not by published port. To route a service like Nginx: 1. Set `ACME_DOMAIN` and `ACME_EMAIL` in `.env` to your real domain and email. 2. In the routed service's `compose.yml` (e.g. `nginx/compose.yml`), remove the `ports:` section and add Traefik labels instead: ```yaml nginx: build: context: ./nginx args: - PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER} - PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT} - CHANGE_SOURCE=${CHANGE_SOURCE} volumes: - ${APP_CODE_PATH_HOST}:${APP_CODE_PATH_CONTAINER} - ${NGINX_HOST_LOG_PATH}:/var/log/nginx - ${NGINX_SITES_PATH}:/etc/nginx/sites-available depends_on: - php-fpm networks: - frontend - backend labels: - "traefik.enable=true" - "traefik.http.services.nginx.loadbalancer.server.port=80" # https router - "traefik.http.routers.https.rule=Host(`${ACME_DOMAIN}`, `www.${ACME_DOMAIN}`)" - "traefik.http.routers.https.entrypoints=https" - "traefik.http.routers.https.middlewares=www-redirectregex" - "traefik.http.routers.https.service=nginx" - "traefik.http.routers.https.tls.certresolver=letsencrypt" # http router - "traefik.http.routers.http.rule=Host(`${ACME_DOMAIN}`, `www.${ACME_DOMAIN}`)" - "traefik.http.routers.http.entrypoints=http" - "traefik.http.routers.http.middlewares=http-redirectscheme" - "traefik.http.routers.http.service=nginx" # middlewares - "traefik.http.middlewares.www-redirectregex.redirectregex.permanent=true" - "traefik.http.middlewares.www-redirectregex.redirectregex.regex=^https://www.(.*)" - "traefik.http.middlewares.www-redirectregex.redirectregex.replacement=https://$$1" - "traefik.http.middlewares.http-redirectscheme.redirectscheme.permanent=true" - "traefik.http.middlewares.http-redirectscheme.redirectscheme.scheme=https" ``` This replaces the port-publishing version (`ports: - "${NGINX_HOST_HTTP_PORT}:80"` etc.), letting Traefik own ports 80/443 on the host and forward to Nginx internally over the `frontend`/`backend` networks. After adding or changing labels on a routed service, apply them: ```bash ./laradock restart nginx ``` ```bash docker compose restart nginx ``` Traefik picks up label changes on the container automatically once it restarts (or, for most label edits, without even restarting Traefik itself, only the routed service). ## The dashboard The dashboard is exposed on `TRAEFIK_DASHBOARD_PORT` (`8888` by default) and protected by basic auth via `TRAEFIK_DASHBOARD_USER`. It's routed by its own labels in `traefik/compose.yml`, gated behind a `Host()` rule matching `ACME_DOMAIN` and the `access-auth` basic-auth middleware. Generate a new bcrypt hash for `TRAEFIK_DASHBOARD_USER` if you want to change the default `admin`/`admin` credentials, then apply it: ```bash ./laradock restart traefik ``` ```bash docker compose restart traefik ``` ## View logs Container logs (Traefik's own startup/ACME/routing log messages): ```bash ./laradock logs traefik ``` ```bash docker compose logs --tail=100 traefik ``` Traefik also writes a separate HTTP **access log**, one line per request, to `traefik/data/access.log` (set via `--accesslog.filepath=/data/access.log` in `traefik/compose.yml`). Tail it directly on your host: ```bash tail -f traefik/data/access.log ``` ## Backup and restore the certificate store Traefik's Let's Encrypt account key and issued certificates live in a single file, `traefik/data/acme.json`, bind-mounted from the repo (not under `DATA_PATH_HOST` like most other services). Losing it means Traefik has to request fresh certificates from Let's Encrypt on next start, which is rate-limited. **Back it up**: ```bash cp traefik/data/acme.json acme.json.bak ``` **Restore it** (Traefik must be stopped first, since it holds the file open): ```bash ./laradock stop traefik ``` ```bash docker compose stop traefik ``` ```bash cp acme.json.bak traefik/data/acme.json chmod 600 traefik/data/acme.json ``` Then start it again with the CLI or Compose command from [Start Traefik](#start-traefik) above. The `600` permission is required, Traefik refuses to use an `acme.json` that's group- or world-readable. ## Force a certificate re-issue (start fresh) To throw away the current ACME account/certificates and have Traefik request everything from scratch (useful if a certificate got issued for the wrong domain, or `acme.json` got corrupted): ```bash ./laradock stop traefik ``` ```bash docker compose stop traefik ``` ```bash rm traefik/data/acme.json touch traefik/data/acme.json chmod 600 traefik/data/acme.json ``` ```bash ./laradock start traefik ``` ```bash docker compose up -d traefik ``` Let's Encrypt rate-limits certificate issuance per domain (currently 5 duplicate certificates per week), so don't do this repeatedly against the same `ACME_DOMAIN` while testing. ## Change the Traefik version The version is pinned in `traefik/Dockerfile` (`FROM traefik:v3.7`), not an env var. Edit the tag to the [release](https://github.com/traefik/traefik/releases) you want, then rebuild: ```bash ./laradock rebuild traefik ``` ```bash docker compose build traefik ``` ## Common issues - **Certificate isn't issued.** Let's Encrypt needs `ACME_DOMAIN` to actually resolve to this host on ports 80/443, and `ACME_EMAIL` to be a real address. Check `traefik/data/acme.json` and the container logs (`./laradock logs traefik`) for ACME errors. - **Routed service still reachable on its old port.** Removing `ports:` isn't enough if you forgot to also remove any override elsewhere; confirm the service's `compose.yml` no longer publishes ports directly. - **Dashboard prompts for a password you don't know.** Default is `admin` / `admin` (`TRAEFIK_DASHBOARD_USER`). Generate your own bcrypt hash and update the `.env` value to change it. - **Traefik can't see other containers.** It needs the Docker socket mounted (`/var/run/docker.sock`, already wired in `traefik/compose.yml`) and the routed service on the same `frontend`/`backend` networks. - **Only one Traefik can bind ports 80/443 per host.** If you're also running another Laradock project's Traefik, or a system-level web server, on the same machine, they'll fight over `TRAEFIK_HOST_HTTP_PORT`/`TRAEFIK_HOST_HTTPS_PORT`. Only one project's Traefik should own 80/443 at a time; give the others different ports or stop them. --- Prefer a simpler reverse proxy with built-in HTTPS? See **[Caddy](https://laradock.io/docs/services/caddy)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Varnish Source: https://laradock.io/docs/services/varnish ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Varnish? [Varnish](https://varnish-cache.org) is an HTTP accelerator that caches responses in memory to serve repeat requests without hitting your app. In Laradock it sits behind Nginx: Nginx listens on 80/443 and forwards to Varnish, and Varnish forwards back to Nginx on port 81 (`VARNISH_BACKEND_PORT`). The shipped config was developed and tested for WordPress but likely works with other systems too; the approach is based on [this Linode guide](https://www.linode.com/docs/websites/varnish/use-varnish-and-nginx-to-serve-wordpress-over-ssl-and-http-on-debian-8/). ## Start Varnish Varnish's own startup checks the backend's availability, so start Nginx first: ```bash ./laradock start nginx ``` ```bash docker compose up -d nginx ``` Then start Varnish itself: ```bash ./laradock start proxy ``` ```bash docker compose up -d proxy ``` The service ships as two containers, `proxy` and `proxy2` (both defined in `varnish/compose.yml`), so it can front two different domains/backends at once. Start the second one the same way if you need it: ```bash ./laradock start proxy2 ``` ```bash docker compose up -d proxy2 ``` ## Stop Varnish Varnish's cache lives entirely in memory (`malloc` storage), so stopping the container **discards the cache**, there's nothing to back up: ```bash ./laradock stop proxy proxy2 ``` ```bash docker compose stop proxy proxy2 ``` To delete the containers entirely: ```bash ./laradock remove proxy proxy2 ``` ```bash docker compose rm -sf proxy proxy2 ``` ## Configuration All settings live in `varnish/defaults.env` and can be overridden by adding the same line to your own `.env`: | Variable | Default | What it does | |---|---|---| | `VARNISH_CONFIG` | `/etc/varnish/default.vcl` | Path to the active VCL config inside the container. | | `VARNISH_PORT` | `6081` | Port Varnish listens on. | | `VARNISHD_PARAMS` | `-p default_ttl=3600 -p default_grace=3600` | Extra flags passed to `varnishd`. | | `VARNISH_PROXY1_CACHE_SIZE` | `128m` | Cache size for the first proxy (`proxy`). | | `VARNISH_PROXY1_BACKEND_HOST` | `workspace` | Domain/host the first proxy serves. | | `VARNISH_PROXY1_SERVER` | `SERVER1` | Server label for the first proxy. | | `VARNISH_PROXY2_CACHE_SIZE` | `128m` | Cache size for the second proxy (`proxy2`). | | `VARNISH_PROXY2_BACKEND_HOST` | `workspace` | Domain/host the second proxy serves. | | `VARNISH_PROXY2_SERVER` | `SERVER2` | Server label for the second proxy. | `VARNISH_BACKEND_PORT` (default `81`, the port Nginx listens on for traffic coming back from Varnish) lives in the project's root `.env`, not `varnish/defaults.env`, since Nginx's `compose.yml` also reads it. These are all read at **container start**, not baked into the image, so after changing any of them in `.env` you need to recreate the container rather than just restart it: ```bash ./laradock start proxy ``` ```bash docker compose up -d proxy ``` `docker compose restart` reuses the existing container as-is and won't pick up the new value; `up -d` recreates it with the current `.env`. Either way the cache is memory-only, so recreating the container is never a data-loss concern here. ## Configure a domain 1. Set your domain in `VARNISH_PROXY1_BACKEND_HOST`. 2. Update your Varnish config and add a matching Nginx config, using `nginx/sites/laravel_varnish.conf.example` as a starting point. 3. Rename `default_wordpress.vcl` to `default.vcl` to use the WordPress-tuned config instead of the older `default.vcl`. ## Serve multiple domains 1. Add a second configuration section to `.env`: ```env VARNISH_PROXY1_CACHE_SIZE=128m VARNISH_PROXY1_BACKEND_HOST=replace_with_your_domain.name VARNISH_PROXY1_SERVER=SERVER1 ``` 2. Add a matching service to `varnish/compose.yml`, modeled on `proxy2`: ```yaml custom_proxy_name: container_name: custom_proxy_name build: ./varnish expose: - ${VARNISH_PORT} environment: - VARNISH_CONFIG=${VARNISH_CONFIG} - CACHE_SIZE=${VARNISH_PROXY2_CACHE_SIZE} - VARNISHD_PARAMS=${VARNISHD_PARAMS} - VARNISH_PORT=${VARNISH_PORT} - BACKEND_HOST=${VARNISH_PROXY2_BACKEND_HOST} - BACKEND_PORT=${VARNISH_BACKEND_PORT} - VARNISH_SERVER=${VARNISH_PROXY2_SERVER} ports: - "${VARNISH_PORT}:${VARNISH_PORT}" links: - workspace networks: - frontend ``` ## Purge and reload **Purge the cache** for a URL (evicts it so the next request goes to the backend again): ```bash curl -X PURGE https://yourwebsite.com/ ``` **Reload Varnish** after changing VCL, without dropping the whole cache: ```bash ./laradock exec proxy varnishreload ``` ```bash docker compose exec proxy varnishreload ``` **Reload Nginx** too if you also changed its site config: ```bash ./laradock exec nginx nginx -t ``` ```bash docker compose exec nginx nginx -t ``` `nginx -t` only validates the config; once it reports no errors, apply it: ```bash ./laradock exec nginx nginx -s reload ``` ```bash docker compose exec nginx nginx -s reload ``` Allowed Varnish CLI commands inside the container: `varnishadm`, `varnishd`, `varnishhist`, `varnishlog`, `varnishncsa`, `varnishreload`, `varnishstat`, `varnishtest`, `varnishtop`. ## Check whether caching is working Open a terminal inside the proxy container: ```bash ./laradock enter proxy ``` ```bash docker compose exec proxy bash ``` Then, from inside the container: - **Live hit/miss stats**: `varnishstat` (add `-1` for a single one-shot snapshot instead of the live dashboard). Look at `cache_hit` vs `cache_miss`, a healthy cache should show `cache_hit` climbing on repeat requests. - **Backend health**: `varnishadm backend.list`. The configured backend (`server1`, from `default.vcl`'s health probe) should show `Healthy`; if it says `Sick`, Varnish can't reach `VARNISH_PROXY1_BACKEND_HOST`/`VARNISH_PROXY1_BACKEND_PORT` and will fail closed to serving errors. - **Per-request trace**: `varnishlog` streams every request live, showing whether each one was a `hit` or a `miss` and why. - **Validate a VCL file before reloading**: `varnishd -C -f /etc/varnish/default.vcl > /dev/null` compiles the file and exits without starting a server, it fails loudly on a syntax error instead of leaving you to debug a crashed reload. ## Common issues - **Varnish container fails to build.** It's expected to be built after Nginx is already up, since it checks the domain's availability at build/start time; run `./laradock start nginx` first. - **Stale content keeps being served.** Purge the cache (`curl -X PURGE ...`) or reload Varnish (`varnishreload`) after deploying changes. - **Wrong backend served.** Confirm `VARNISH_PROXY1_BACKEND_HOST`/`VARNISH_PROXY2_BACKEND_HOST` match the domain in the corresponding Nginx site config, and that you're using `default_wordpress.vcl` (renamed to `default.vcl`) if following the WordPress setup. - **Changed `.env` but nothing happened.** `VARNISH_PORT`, `VARNISHD_PARAMS`, and the cache size/backend variables are only read when the container is created. `./laradock restart proxy` reuses the old values; run `./laradock start proxy` again to recreate it with the new `.env`. - **Cache is always empty after a deploy.** Expected: the cache is in-memory only (`malloc` storage), so it's wiped every time the container stops, restarts, or is recreated, not just when you purge it manually. - **`varnishadm backend.list` shows `Sick`.** The health probe in `default.vcl`/`default_wordpress.vcl` can't reach the backend on `BACKEND_HOST`/`BACKEND_PORT`. Confirm the backend service (usually `workspace`, per `VARNISH_PROXY1_BACKEND_HOST`) is running and listening on the expected port. --- Varnish sits in front of **[Nginx](https://laradock.io/docs/services/nginx)**; for balancing across multiple Varnish instances see **[HAProxy](https://laradock.io/docs/services/haproxy)**. New to Laradock? Start with **[Getting Started](https://laradock.io/docs/getting-started)**. ================================================================ # Run Adminer on Docker Source: https://laradock.io/docs/adminer-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Adminer? [Adminer](https://www.adminer.org) is a lightweight, single-file database administration tool that supports MySQL, MariaDB, PostgreSQL, SQLite, MS SQL and more from one simple interface. It is not an application with its own database; it is a PHP frontend that connects to a database server you already have running, prized for being far smaller and simpler than heavier admin UIs. ## Why run Adminer in Docker? Docker packages Adminer (a small PHP application under the hood) into an isolated container that runs the same on every machine. Instead of installing PHP onto your laptop just to run a database GUI, or downloading a single PHP file and figuring out how to serve it, you run a disposable container that connects straight to whichever database container is already part of your stack, and vanishes cleanly when you delete it. The catch: wiring a database admin UI to the right container, network and credentials yourself is fiddly enough that most people skip it. That is exactly what Laradock removes, because it is already done. ## Why Laradock is the best fit for Adminer Unlike most of the other projects in this guide, Adminer is not something you add to Laradock: Laradock already ships it as a ready-to-use built-in service (see [Use Adminer](https://laradock.io/docs/services/adminer)). There is no install step, no codebase to clone, no config file to write, just a service to switch on: - **One line to turn on.** `./laradock start adminer` (or `docker compose up -d adminer`) and it is ready to point at any database container in your stack. - **Works with more than MySQL.** Adminer's single interface talks to MySQL, MariaDB, PostgreSQL and others, matching whatever database service you already picked in Laradock. - **Nothing is hidden and you own everything.** No generated files, no magic. The `adminer/compose.yml` and its Dockerfile are right there for you to read and edit. - **Fits whatever else you are running.** Laradock is framework-agnostic, so the same Adminer service works whether the app behind that database is Laravel, WordPress, or plain PHP. Concretely, Laradock's Adminer service is pre-wired to talk to your database containers over the internal Docker network, with its port, default server, theme and plugins all controlled from `.env`. ## Run Adminer on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-project git clone https://github.com/laradock/laradock.git cd laradock ``` ### 2. Start your database and Adminer Adminer needs a database to point at. Start both together: ```bash ./laradock start mysql adminer ``` ```bash cp .env.example .env docker compose up -d mysql adminer ``` Using PostgreSQL or MariaDB instead? Start that service and point Adminer's login screen at it by default: ```env ADM_DEFAULT_SERVER=postgres ``` ```bash ./laradock start postgres adminer ``` ```bash docker compose up -d postgres adminer ``` The full catalog of other services is [here](https://laradock.io/docs/Intro#supported-services). ### 3. Point Adminer at the containers There is nothing to configure by hand: Adminer's login screen asks for a server, and `ADM_DEFAULT_SERVER` in `.env` pre-fills it with the container name (`mysql` by default). Use the same credentials as the database container itself, `default` / `secret` for the stock `mysql` service from `mysql/defaults.env`, unless you overrode them in Laradock's `.env` (it always wins). ### 4. Open and log in ```bash ./laradock start mysql adminer ``` ```bash docker compose up -d mysql adminer ``` Then open [http://localhost:8081](http://localhost:8081) (the default `ADM_PORT`) and log in with system `MySQL`, server `mysql`, user `default`, password `secret`, or whatever you overrode those to. If you are running Adminer alongside phpMyAdmin, note they share the same default port; set `ADM_PORT` to something else in `.env` so both can run at once. ## Change the PHP version anytime Adminer's own container is built and versioned by Laradock independently of the `PHP_VERSION` your application uses, so there is nothing to change here for a typical setup. If you do need to rebuild the service after editing `adminer/Dockerfile`, the same pattern applies to it as to every other Laradock service: `./laradock rebuild adminer` (or `docker compose build adminer`). ## Frequently Asked Questions ### Do I need to install Adminer or PHP to use it with Laradock? No. It is already a built-in Laradock service; `docker compose up -d adminer` is the entire install step. ### Which services should I start to use Adminer? The database you want to browse, plus `adminer`, for example `mysql adminer` or `postgres adminer`. No web server or workspace container is required just to browse the database. ### Can Adminer connect to more than one database at a time? Yes. Adminer's login screen lets you pick the server, system and credentials each time you sign in, so one running Adminer container can browse any database container it can reach on the Docker network, not just the one in `ADM_DEFAULT_SERVER`. ### Is phpMyAdmin a better fit than Adminer? Both ship as built-in Laradock services and both connect to the same database containers. Adminer is a single lightweight file that also speaks PostgreSQL and other engines; phpMyAdmin has a deeper feature set focused specifically on MySQL/MariaDB. See [Run phpMyAdmin on Docker](https://laradock.io/docs/phpmyadmin-on-docker) for the same walkthrough with phpMyAdmin. ### Is this the same setup I would use in production? Most teams do not expose Adminer in production at all, since it is a convenience tool for local and staging work. If you do run it somewhere reachable, put it behind authentication and network restrictions; see [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the general hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Akaunting on Docker Source: https://laradock.io/docs/akaunting-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Akaunting? [Akaunting](https://akaunting.com) is an open source online accounting platform for invoicing, expense tracking and double-entry bookkeeping, built on Laravel with a modular "apps" system for extending it. An Akaunting instance is a PHP application backed by MySQL, MariaDB, PostgreSQL or SQLite, served through a web server, with Artisan handling installation, migrations and sample data. ## Why run Akaunting in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL, Redis) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Akaunting instance can run PHP 8.3 while another project runs an older version, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Akaunting Akaunting has no official Docker image maintained by the core project; self-hosters typically build their own image or use a community one. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Akaunting today, add a WordPress site or a plain Laravel API beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so Akaunting gets exactly the runtime its current release needs. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit, useful when you add or build a custom Akaunting app/module. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other Laravel-based project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Akaunting it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB/PostgreSQL ready to connect (and Redis one command away when you want caching), and a `workspace` container with Composer, Node, npm and Artisan already installed. ## Run Akaunting on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-akaunting-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Akaunting codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs Akaunting needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL instead? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Redis is not required to boot Akaunting; it defaults to file-based cache. Add it later for a speed-up: see [Add Redis caching](#add-redis-caching-optional) below. Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Akaunting at the containers In Akaunting's `.env`, use the service names as hostnames: ```env DB_HOST=mysql ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, where Composer, Node, npm and Artisan live, and run Akaunting's CLI installer: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash composer install php artisan install --db-name="default" --db-username="default" --db-password="secret" \ --admin-email="you@example.com" --admin-password="secret" ``` Add `php artisan sample-data:seed` afterwards if you want demo data. Then open [http://localhost](http://localhost). That is a full Akaunting instance running on Docker. ## Add Redis caching (optional) Redis is not required, but because Akaunting is a Laravel app it can use Redis for cache and sessions with no plugin, just config. Two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point Akaunting at it in its `.env` (the service name is the host): ```env CACHE_DRIVER=redis SESSION_DRIVER=redis REDIS_HOST=redis ``` That is it. Without those lines the Redis container just sits idle, which is why the required stack above leaves it out. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.2 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Akaunting requires PHP 8.1 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Akaunting instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your instance live When your Akaunting instance is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run Akaunting with Laradock? No. Everything lives inside the containers. Composer, Node, npm and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Akaunting instance? `nginx mysql workspace` is all Akaunting requires: web server, database, and a shell. Swap `mysql` for `postgres` if you prefer. Add `redis` only when you want caching, see [Add Redis caching](#add-redis-caching-optional). ### Can I run multiple Akaunting instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot for `vendor/`-heavy apps); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Aureus ERP on Docker Source: https://laradock.io/docs/aureus-erp-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Aureus ERP? [Aureus ERP](https://aureuserp.com) is an open-source ERP platform built on Laravel and FilamentPHP. It ships as a set of installable modules, accounting/finance, inventory, sales, CRM, HR and recruitment, and purchasing among them, so a business can start with only the modules it needs and add more later. Under the hood it is a Laravel application with a Filament admin panel, which means it needs the same infrastructure as any Laravel app: a web server, a PHP runtime, and a database, with Redis recommended once you move past a single-user trial. ## Why run Aureus ERP in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL, Redis) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. Aureus ERP's own requirements are fairly specific too (PHP 8.2+, generous memory and execution-time limits, particular PHP extensions), and Docker means you never have to fight your host machine to match them. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Aureus ERP The Aureus ERP repository does ship a `docker-compose.yml`, but it is the standard Laravel Sail file (a `laravel.test` app container plus MySQL, Redis and Mailpit), not a purpose-built ERP deployment tool. It is a fine quick trial, but it is still just Sail, so the same tradeoffs apply: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Aureus ERP today, add a separate reporting service, a Symfony API, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the short list Sail's default compose file gives you. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For Aureus ERP specifically, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL ready to connect (and Redis one command away when you want caching), and a `workspace` container with Composer, Node and Artisan already installed, so the ERP's PHP-extension and memory requirements are handled by the image instead of your host. ## Run Aureus ERP on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-aureus-erp-app git clone https://github.com/laradock/laradock.git cd laradock ``` (No Aureus ERP files yet? Clone Laradock first, then pull Aureus ERP from the workspace container in the next steps.) ### 2. Pick the services Aureus ERP needs Aureus ERP needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` MySQL 8.0+ is what Aureus ERP recommends; the full service catalog (including alternatives) is [here](https://laradock.io/docs/Intro#supported-services). Redis is not required to boot Aureus ERP, but it is worth adding once you move past a single-user trial. See [Add Redis caching](#add-redis-caching-optional) below. Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Aureus ERP at the containers Aureus ERP is a standard Laravel app, so in its `.env`, use the service names as hostnames: ```env DB_CONNECTION=mysql DB_HOST=mysql ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run Aureus ERP Enter the `workspace` container, where Composer, Node and Artisan live, and run the project's own installer: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash composer install cp .env.example .env php artisan key:generate php artisan erp:install ``` `erp:install` runs the migrations and seeders, sets up Filament Shield roles and permissions, and walks you through creating an admin account. Then open [http://localhost](http://localhost). That is a full Aureus ERP install running on Docker. ## Add Redis caching (optional) Redis is not required, but because Aureus ERP is a Laravel app it can use Redis for cache and sessions with no plugin, just config, which helps once more than one person is using it. Two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point Aureus ERP at it in its `.env` (the service name is the host): ```env CACHE_STORE=redis SESSION_DRIVER=redis REDIS_HOST=redis ``` That is it. Without those lines the Redis container just sits idle, which is why the required stack above leaves it out. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Aureus ERP asks for PHP 8.2 or higher; set it in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Bump it later to track a new Aureus ERP release, all without touching anything installed on your host. ## Take your install live When your Aureus ERP install is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, Composer or MySQL to run Aureus ERP with Laradock? No. Everything lives inside the containers. Composer, Node and Artisan are all in the `workspace` container; you never install PHP or MySQL on your host. ### Which services should I start for Aureus ERP? `nginx mysql workspace` is all Aureus ERP requires: web server, database, and a shell with the tooling you need. Aureus ERP recommends MySQL 8.0+; SQLite is an option for a minimal trial but is not recommended for real use. Add `redis` once you go past a single-user trial, see [Add Redis caching](#add-redis-caching-optional). ### Does Aureus ERP need more resources than a typical Laravel app? Its own documentation recommends generous PHP memory and execution-time limits and at least 4GB of RAM on the host, since it is running an admin panel and multiple business modules at once. Give the containers enough memory in your Docker settings accordingly. ### Can I run Aureus ERP alongside other PHP projects on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than the default Sail compose file. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run AzuraCast on Docker Source: https://laradock.io/docs/azuracast-on-docker ================================================================ ## What is AzuraCast? [AzuraCast](https://www.azuracast.com) is a self-hosted platform for running internet radio stations: it manages streaming (via Icecast/Liquidsoap), playlists, scheduling, a web-based DJ/admin panel and listener analytics. It is a full station management system, not a small app you drop a web server in front of. ## Why run AzuraCast in Docker? Docker packages a stack this size (web panel, database, cache, streaming daemons, background workers) into isolated containers that run the same on every machine, instead of installing all of that natively and managing version drift and service conflicts by hand. For a platform with this many moving parts, that isolation matters even more than for a typical PHP app. ## Why Laradock is not the natural fit here Unlike every other project in this series, AzuraCast is not a good match for "add it as an app inside Laradock's containers", and it would be dishonest to pretend otherwise. AzuraCast ships and requires its own complete, self-managed Docker Compose stack. Its official installer (`docker.sh`) downloads and manages its own `docker-compose.yml`, provisioning its own internal NGINX, MariaDB, Redis, and the streaming/worker containers it needs, and it owns their lifecycle (updates, backups, service restarts) through that same script. This is not an optional convenience; it is effectively the only supported way to run AzuraCast. Running AzuraCast's application code inside Laradock's `nginx`/`php-fpm`/`mysql` containers would mean fighting that internal orchestration: AzuraCast's own compose file expects to own its database and cache, its own container names and networking, and its own update path. You would be maintaining a fork of AzuraCast's deployment model instead of using it, with no real benefit over just running AzuraCast's installer. **If you want to run AzuraCast, use its own official installer** on a host with Docker installed: ```bash mkdir -p /var/azuracast cd /var/azuracast curl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/main/docker.sh > docker.sh chmod a+x docker.sh ./docker.sh install ``` That script sets up AzuraCast's full stack correctly and keeps it updatable. Full instructions are in [AzuraCast's own Docker documentation](https://www.azuracast.com/docs/getting-started/installation/docker/). ### If you want to experiment anyway If you already run other PHP projects behind Laradock and just want to poke at AzuraCast's codebase (development, not a real station), run AzuraCast's own compose stack as a separate, independent set of containers alongside Laradock, on different ports. Do not try to point Laradock's `nginx`/`mysql`/`php-fpm` at AzuraCast's application code; it is not built to run that way, and its installer assumes full ownership of its own containers. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Looking for a PHP project that does fit Laradock's pattern? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run bbPress on Docker Source: https://laradock.io/docs/bbpress-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is bbPress? [bbPress](https://bbpress.org) is the official forum plugin for WordPress, adding forums, topics and replies as first-class WordPress content on top of a regular WordPress install. It is not a standalone application; it requires a working WordPress site first, which means the same underlying stack as any WordPress site: a web server, PHP-FPM, a MySQL or MariaDB database, and Redis for object caching once a forum has real traffic. ## Why run bbPress in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL, Redis) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between sites and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One forum can run PHP 8.3 while another WordPress site runs an older 7.4 plugin stack, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for bbPress bbPress has no Docker tooling of its own, and neither does WordPress, so a ready-made, no-lock-in environment matters even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your bbPress-powered forum today, add a Laravel API, a headless storefront, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so a legacy WordPress theme and a modern forum each get exactly the runtime they need. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for bbPress it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB ready to connect (and Redis one command away when you want object caching), a `workspace` container with WP-CLI, Composer and git installed, and any PHP version behind a single line of config. ## Run bbPress on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-bbpress-forum git clone https://github.com/laradock/laradock.git cd laradock ``` (No WordPress files yet? Clone Laradock first, then download WordPress from the `workspace` container in the next steps; bbPress is installed on top of it as a plugin.) ### 2. Pick the services your forum needs bbPress needs exactly what WordPress needs: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB over MySQL? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis?** Not to get running. WordPress and bbPress do nothing with Redis on their own, a fresh forum runs perfectly on `nginx mysql workspace`. It only helps once a forum has real traffic, and only after you add the object-cache plugin. See [Add Redis object caching](#add-redis-object-caching-optional) below when you actually want it. ### 3. Point WordPress at the containers In your `wp-config.php`, use the service names as hostnames, same as any WordPress install: ```php define( 'DB_HOST', 'mysql' ); define( 'DB_NAME', 'default' ); define( 'DB_USER', 'default' ); define( 'DB_PASSWORD', 'secret' ); ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install WordPress, then install bbPress Enter the `workspace` container, where WP-CLI, Composer and git live, set WordPress up, then add bbPress on top: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash wp core download # only if you have no WordPress files yet wp core install --url=http://localhost --title="My Community" \ --admin_user=admin --admin_password=secret --admin_email=you@example.com wp plugin install bbpress --activate ``` Then open [http://localhost/wp-admin](http://localhost/wp-admin) and check Settings > Forums; bbPress creates default forum pages you can use right away, or customize before opening [http://localhost/forums](http://localhost/forums). That is a full bbPress forum running on Docker. ## Add Redis object caching (optional) Redis is not required, but once a forum has real traffic it caches WordPress's database queries in memory and noticeably speeds up the admin and front end. Wiring it up is three steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point WordPress at it in `wp-config.php`: ```php define( 'WP_REDIS_HOST', 'redis' ); ``` 3. From the `workspace` container, install and enable the [Redis Object Cache](https://wordpress.org/plugins/redis-cache/) plugin: ```bash wp plugin install redis-cache --activate wp redis enable ``` That's it, your forum now stores its object cache in Redis. Without those steps the container just sits idle, which is why the required stack above leaves it out. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` bbPress follows WordPress's own PHP support, which currently recommends PHP 7.4 or newer (8.x is the modern default); Laradock covers anything from PHP 5.6 to 8.5, so a legacy site pinned to an old theme and a brand-new build run side by side, each isolated, none of it installed on your machine. ## Take your forum live When your forum is ready, the same Laradock stack becomes your deployment. You build one hardened image of your site and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, MySQL or WP-CLI to run bbPress with Laradock? No. Everything lives inside the containers. WP-CLI, Composer, git and PHP are all provided; you never install them on your host. ### Which services should I start for a typical bbPress forum? `nginx mysql workspace` is all bbPress requires: web server, database, and a shell. Swap `mysql` for `mariadb` if you prefer. Add `redis` only if you set up the [object-cache plugin](#add-redis-object-caching-optional); without it, Redis does nothing for WordPress or bbPress. ### Can I run multiple bbPress forums on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run BookStack on Docker Source: https://laradock.io/docs/bookstack-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is BookStack? [BookStack](https://www.bookstackapp.com) is an open source platform for organizing documentation into a shelf, book, chapter, page hierarchy, popular as a self-hosted alternative to wiki and knowledge-base tools. It is built on the Laravel framework, so a BookStack instance is a PHP application backed by a MySQL or MariaDB database, served through a web server, with Artisan handling migrations and setup tasks just like any other Laravel app. Its search runs on the database itself, so there is no separate search engine to install, and it can optionally use Redis for cache, sessions and background queues. ## Why run BookStack in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One BookStack instance can run on an older PHP version while another project runs the latest PHP, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for BookStack BookStack has no official Docker image of its own beyond a few community-maintained ones, so a ready-made, no-lock-in environment matters even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your BookStack instance today, add a WordPress marketing site, a plain Laravel API, or any other PHP project beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus a single-purpose image with a narrow set of tags. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other Laravel-based project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for BookStack it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB ready to connect, a `workspace` container with Composer, git and Artisan already installed, and Redis, a MailHog catcher and a queue worker each one command away when you want them. ## Run BookStack on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-bookstack-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No BookStack codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs BookStack needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, and search runs on the database, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB instead? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis?** Not to get running. BookStack defaults to file cache, file sessions and a synchronous queue, so a fresh instance runs perfectly on `nginx mysql workspace`. Redis only helps once you switch those drivers over to it. See [Add Redis](#add-redis-for-cache-sessions-and-queues-optional) below when you want it. ### 3. Point BookStack at the containers In BookStack's `.env`, use the service names as hostnames: ```env APP_URL=http://localhost DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). `APP_URL` matters in BookStack: every link it generates is built from that value. ### 4. Install and run your instance Enter the `workspace` container, where Composer, git and Artisan live, place the BookStack codebase, then run its setup: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then, inside the container: ```bash git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch . # only if you have no codebase yet composer install --no-dev cp .env.example .env php artisan key:generate php artisan migrate ``` The `release` branch ships with its front-end assets pre-built, so you do not need Node for a standard install (see [Build the front-end assets](#build-the-front-end-assets-development-branch) if you work from `development` instead). Then open [http://localhost](http://localhost). BookStack seeds a default admin login of `admin@admin.com` / `password`. Sign in and change it immediately, or skip the default and create your own admin from the workspace: ```bash php artisan bookstack:create-admin --email you@example.com --name "You" --password "a-strong-password" ``` ## Add Redis for cache, sessions and queues (optional) Redis is not required, but on a busier instance it takes cache and session storage off the database and lets background jobs run out of process. Wiring it up is two steps. 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point BookStack at it in its `.env`. BookStack uses a single `REDIS_SERVERS` line in `HOST:PORT:DATABASE` form, not the usual `REDIS_HOST`: ```env CACHE_DRIVER=redis SESSION_DRIVER=redis REDIS_SERVERS=redis:6379:0 ``` That switches cache and sessions to Redis. To also move background jobs onto it, set `QUEUE_CONNECTION=redis` and run a worker, covered next. ## Run a queue worker for async email (optional) By default BookStack's `QUEUE_CONNECTION` is `sync`, so email and other jobs run inline during the web request and no worker is needed. On a real instance you usually want them off the request path: set the connection to `database` (no extra service) or `redis`, then run a worker. 1. In BookStack's `.env`: ```env QUEUE_CONNECTION=database ``` Use `redis` here instead if you enabled Redis above. `database` needs no extra container; it queues jobs into a table. 2. Run the worker from the `workspace` container: ```bash php artisan queue:work ``` For a supervised worker that restarts on its own, Laradock ships a dedicated `php-worker` container (Supervisor-managed), and `laravel-horizon` if you run the Redis queue and want its dashboard. Start either with `./laradock start php-worker`. BookStack has no required cron scheduler; its background work flows through this queue, not a `schedule:run` cron. ## Send email through MailHog (optional) BookStack sends invitations, notifications and password resets by email. Laradock's `mailhog` container catches every outgoing message in a web inbox so you can read them without a real SMTP account. 1. Start MailHog: ```bash ./laradock start mailhog ``` ```bash docker compose up -d mailhog ``` 2. Point BookStack's mail at the container in its `.env`: ```env MAIL_DRIVER=smtp MAIL_HOST=mailhog MAIL_PORT=1025 MAIL_ENCRYPTION=null MAIL_USERNAME=null MAIL_PASSWORD=null ``` Open [http://localhost:8025](http://localhost:8025) to read anything BookStack sends. Swap in your real SMTP host, port and credentials when you go live. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current BookStack releases need PHP 8.2 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older BookStack instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Rebuild the search index BookStack's search is a table it maintains inside your database, so there is no Elasticsearch or OpenSearch to run. After a bulk import, a restored database, or if results ever look stale, rebuild the index from the `workspace` container: ```bash php artisan bookstack:regenerate-search ``` That is the whole search story: no extra container, no config, just this one command when the index needs a refresh. ## Admin and maintenance commands BookStack ships a set of Artisan commands you run from inside the `workspace` container. The common ones: ```bash php artisan bookstack:create-admin # create an admin user (add --email, --name, --password to skip prompts) php artisan bookstack:reset-mfa # clear a user's multi-factor methods if they are locked out php artisan bookstack:update-url OLD NEW # rewrite stored links after changing domain, e.g. http://localhost https://docs.example.com php artisan bookstack:regenerate-permissions # rebuild access control after a bulk change php artisan bookstack:regenerate-references # rebuild cross-item links php artisan bookstack:cleanup-images --force # delete images no longer referenced by any page ``` Enter the container first with `./laradock workspace` (or `docker compose exec workspace bash`), then run any of these. ## Build the front-end assets (development branch) If you cloned the `release` branch above, the CSS and JS are already built and you can skip this. If you work from the `development` branch instead, build the assets once (and after front-end changes) from the `workspace` container, which has Node and npm installed: ```bash npm ci npm run build ``` ## Import an existing BookStack database Moving an instance onto Laradock? Copy its SQL dump into the Laradock folder (so the `workspace` container can see it), then load it into the `mysql` container: ```bash ./laradock workspace mysql -h mysql -u default -p default < /var/www/backup.sql ``` The password is `secret` unless you changed it. After importing, fix any hard-coded links to the old address and rebuild the search index: ```bash php artisan bookstack:update-url https://old-host.example https://localhost php artisan bookstack:regenerate-search ``` Uploaded files and images live under BookStack's `storage/` and `public/uploads/` directories, so copy those across too if the dump does not include them. ## Take your instance live When your BookStack instance is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run BookStack with Laradock? No. Everything lives inside the containers. Composer, git, Node and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical BookStack instance? `nginx mysql workspace` covers it: web server, database, and a shell. Swap `mysql` for `mariadb` if you prefer. BookStack's search runs on the database, so there is no separate search engine to add. Bring in `redis`, `mailhog` or `php-worker` only when you want Redis caching, an email inbox, or an out-of-process queue, each covered in its own section above. ### Does BookStack need Redis, a search engine, or a cron job? No to all three by default. It ships with file cache and sessions, a synchronous queue, and database-backed search, so a fresh instance runs on just `nginx mysql workspace`. Redis and a queue worker are optional upgrades, and BookStack has no required scheduled/cron task. ### Can I run multiple BookStack instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot for `vendor/`-heavy apps); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Cachet on Docker Source: https://laradock.io/docs/cachet-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Cachet? [Cachet](https://cachethq.io) is an open source, self-hosted status page system for publishing incident history and component uptime, built on Laravel. A Cachet instance is a PHP application backed by MySQL, MariaDB, PostgreSQL or SQLite, served through a web server, with Artisan handling installation and migrations. Worth knowing before you commit to it: the last stable v2 release shipped in November 2023, and a v3 rewrite (Laravel, Inertia, Vue) has been in public progress since 2023 without a committed release date, so treat the project's pace as slow rather than dead, and check its GitHub activity for the current state before depending on it. ## Why run Cachet in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Cachet instance can run on a specific PHP version while another project runs a different one, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Cachet Cachet has no actively maintained official Docker image of its own; older community images exist but track the project's own slow pace. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Cachet today, add a Laravel API or a WordPress site beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, useful given how long a slow-moving project like this can sit on an older PHP version. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit, which matters when a project's own tooling has stalled. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other Laravel-based project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Cachet it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB/PostgreSQL already wired, and a `workspace` container with Composer, git and Artisan already installed. ## Run Cachet on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-cachet-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Cachet codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs Cachet needs a web server and a database. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL instead? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Cachet at the containers In Cachet's `.env`, use the service names as hostnames: ```env DB_CONNECTION=mysql DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, where Composer, git and Artisan live, clone or place the Cachet codebase, and run its setup: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then, inside the container: ```bash git clone https://github.com/cachethq/cachet.git --branch 2.4 --single-branch . # only if you have no codebase yet composer install --no-dev -o cp .env.example .env php artisan key:generate php artisan cachet:install ``` Then open [http://localhost](http://localhost). That is a full Cachet instance running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.2 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Cachet's current stable release targets PHP 8.2 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Cachet instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your status page live When your Cachet instance is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run Cachet with Laradock? No. Everything lives inside the containers. Composer, git and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Cachet instance? `nginx mysql workspace` covers it: web server, database, and a shell. Swap `mysql` for `postgres` if you prefer. ### Is Cachet still being actively developed? The pace is slow: the last stable v2 release was November 2023, and a v3 rewrite has been publicly in progress since 2023 without a committed date. It still installs and runs; check the project's GitHub activity before depending on it for anything critical. ### Can I run multiple Cachet instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Crater on Docker Source: https://laradock.io/docs/crater-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Crater? [Crater](https://craterapp.com) is an open source invoicing and expense-tracking app for freelancers and small businesses, built on Laravel with a Vue frontend. A Crater instance is a PHP application backed by a MySQL or MariaDB database, served through a web server, with Composer and a browser-based setup wizard handling installation. Release activity has slowed noticeably in the last couple of years; the codebase still works and is worth self-hosting, but check the project's GitHub activity before relying on it for anything mission-critical. ## Why run Crater in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Crater instance can run on an older, pinned PHP version while another project runs the latest PHP, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Crater Crater has no official Docker image from the core project itself, only a handful of community-maintained ones. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Crater today, add a WordPress site or a plain Laravel API beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, useful given how long an install like Crater can sit on an older PHP version between updates. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit, which matters for a project whose upstream activity you may need to patch around yourself. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other Laravel-based project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Crater it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB already wired, and a `workspace` container with Composer, Node, npm and git already installed. ## Run Crater on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-crater-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Crater codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs Crater needs a web server and a database. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB instead? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Crater at the containers In Crater's `.env`, use the service names as hostnames: ```env DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, where Composer, Node and npm live, clone or place the Crater codebase, and prepare it: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then, inside the container: ```bash git clone https://github.com/crater-invoice-inc/crater.git --single-branch . # only if you have no codebase yet composer install cp .env.example .env php artisan key:generate ``` Then open [http://localhost](http://localhost) and complete Crater's browser-based install wizard, which writes the rest of the configuration and runs the migrations for you. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.2 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Crater targets PHP 7.4 and newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Crater instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your instance live When your Crater instance is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run Crater with Laradock? No. Everything lives inside the containers. Composer, Node, npm and git are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Crater instance? `nginx mysql workspace` covers it: web server, database, and a shell. Swap `mysql` for `mariadb` if you prefer. ### Is Crater still actively maintained? Release activity has slowed compared to its early years; check the project's GitHub repository for the current pace before depending on it for production invoicing. It still installs and runs fine on a supported PHP version either way. ### Can I run multiple Crater instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run DokuWiki on Docker Source: https://laradock.io/docs/dokuwiki-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is DokuWiki? [DokuWiki](https://www.dokuwiki.org) is an open source wiki application known for one thing above all: it has no database. Pages, revisions and media are stored as plain text files on disk, in the `data/` directory, which makes backups a simple file copy and the whole thing easy to reason about. It is a PHP application served through a web server; that is the entire stack it needs. ## Why run DokuWiki in Docker? Docker packages the pieces DokuWiki actually needs (NGINX, PHP-FPM) into isolated containers that run the same on every machine. Instead of installing PHP onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One wiki can run on an older PHP version to keep a legacy plugin working, while another project runs the latest PHP, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for DokuWiki DokuWiki has no official Docker image or first-party runtime of its own, so a ready-made, no-lock-in environment matters even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your DokuWiki site today, add a Laravel API, a WordPress marketing site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so a legacy plugin-heavy wiki and a fresh install each get exactly the runtime they need. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for DokuWiki it gives you a production-style NGINX + PHP-FPM stack and a `workspace` container with git and the file tools you need to unpack the DokuWiki archive; there is no database service to wire up at all. ## Run DokuWiki on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-dokuwiki-site git clone https://github.com/laradock/laradock.git cd laradock ``` (No DokuWiki files yet? Clone Laradock first, then download and extract the DokuWiki package from the workspace container in the next steps.) ### 2. Pick the services your wiki needs DokuWiki only needs a web server; there is no database to start. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx workspace ``` ```bash cp .env.example .env docker compose up -d nginx workspace ``` Prefer Apache or Caddy instead? Swap the name: `./laradock start apache2 workspace` (or `docker compose up -d apache2 workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point DokuWiki at your project There is no database host to configure. Just make sure DokuWiki's `data/`, `conf/` and related directories are writable by the web server user inside the container, since that is where all content and configuration is stored as plain files. ### 4. Install and run your wiki Enter the `workspace` container, place the DokuWiki files in your project's web root (download the archive from [dokuwiki.org](https://www.dokuwiki.org) and extract it if you have not already): ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then open [http://localhost/install.php](http://localhost/install.php) and finish DokuWiki's browser installer: it checks file permissions, asks for a wiki name and admin account, and writes the configuration to `conf/local.php`. Remove or lock down `install.php` once it is done, as DokuWiki's own docs recommend. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.2 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current DokuWiki releases need PHP 8.0 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older wiki pinned to a legacy plugin and a brand-new install side by side, each isolated, none of it installed on your machine. ## Take your wiki live When your wiki is ready, the same Laradock stack becomes your deployment. You build one hardened image of your site and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP to run DokuWiki with Laradock? No. Everything lives inside the containers. PHP and its required extensions are already there; you never install them on your host. ### Which services should I start for a typical DokuWiki site? `nginx workspace` covers it: web server and a shell. There is no database service to add, since DokuWiki stores everything as flat files. ### Can I run multiple DokuWiki sites on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Dolibarr on Docker Source: https://laradock.io/docs/dolibarr-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Dolibarr? [Dolibarr](https://www.dolibarr.org) is an open-source ERP and CRM: a single PHP application covering invoicing, orders, stock, CRM, HR and accounting for small and mid-size businesses. It is known for being modular, you enable only the features you need, and for shipping as a self-contained PHP codebase with a browser-based install wizard rather than a build step. What it genuinely needs is a web server, a PHP runtime, and a database (MySQL, MariaDB or PostgreSQL); Redis is optional but helps on busier installs. ## Why run Dolibarr in Docker? Docker packages each of those pieces (a web server, PHP-FPM, MySQL/MariaDB/PostgreSQL, Redis) into isolated containers that run the same on every machine. Instead of installing PHP and a database onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Dolibarr install can run PHP 8.3 while another project on the same computer runs a completely different stack, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Dolibarr Dolibarr does publish an official Docker image (`dolibarr/dolibarr`, maintained at [Dolibarr/dolibarr-docker](https://github.com/Dolibarr/dolibarr-docker)), but it is a single all-in-one container: PHP, Apache and Dolibarr baked together, with no database included and no workspace, cache or multi-service orchestration around it. You still have to hand-wire a database container and everything else yourself. Here is why Laradock is the better fit for a real dev environment: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Dolibarr today, add a Laravel API, a WordPress site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus a single fixed image with one PHP version baked in. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Dolibarr it gives you a production-style NGINX (or Apache) + PHP-FPM stack, MySQL/MariaDB/PostgreSQL ready to connect (and Redis one command away when you want caching), and a `workspace` container with Composer, git and PHP CLI installed for any maintenance scripts. ## Run Dolibarr on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-dolibarr-app git clone https://github.com/laradock/laradock.git cd laradock ``` (No Dolibarr files yet? Clone Laradock first, then download Dolibarr from the [official releases](https://www.dolibarr.org/downloads) or via the workspace container in the next steps.) ### 2. Pick the services your Dolibarr install needs Dolibarr needs exactly two things: a web server and a database. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB or PostgreSQL? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`) or `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis?** Not to get running. A fresh Dolibarr install runs perfectly on `nginx mysql workspace`. Redis only helps on busier installs, and only once you enable and point Dolibarr's cache at it. See [Add Redis caching](#add-redis-caching-optional) below when you actually want it. ### 3. Point Dolibarr at the containers Dolibarr does not use a `.env` file for its own configuration; the install wizard writes the database connection into `htdocs/conf/conf.php` for you. When the wizard asks for the database host, user and password, use the service names and credentials from Laradock: ``` Database host: mysql Database name / user / password: from mysql/defaults.env ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your app Open [http://localhost](http://localhost). Dolibarr has no Artisan- or WP-CLI-style installer; instead its browser-based setup wizard walks you through the license, a set of environment checks, and the database connection form from step 3, then creates `conf/conf.php` and the admin account for you. If you need a shell for Composer, git or a maintenance script, it lives in the workspace container: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` That is a full Dolibarr install running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Dolibarr requires PHP 8.1 or newer, with 8.2/8.3 recommended for the best compatibility and performance. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` So a Dolibarr install pinned to an older PHP release and a brand-new one run side by side, each isolated, none of it installed on your machine. ## Add Redis caching (optional) Redis is not required, but on a busier install it can hold Dolibarr's cache in memory instead of on disk. Wiring it up is two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point Dolibarr's cache at it. In `htdocs/conf/conf.php`, set the memcached-compatible cache host to the service name: ```php $dolibarr_main_prod = 1; $dolibarr_main_force_https = 0; $dolibarr_nocsrfcheck = 0; // Cache backend $dolibarr_main_memcached_host = 'redis'; ``` Without those steps the Redis container just sits idle, which is why the required stack above leaves it out. ## Take your app live When your Dolibarr install is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or a database to run Dolibarr with Laradock? No. Everything lives inside the containers. PHP, Composer and git are all available in the `workspace` container; you never install them on your host. ### Which services should I start for a typical Dolibarr install? `nginx mysql workspace` is all Dolibarr requires: web server, database, and a shell. Swap `mysql` for `mariadb` or `postgres` if you prefer. Add `redis` only if you wire up Dolibarr's [cache](#add-redis-caching-optional); without it, Redis does nothing for Dolibarr. ### Can I run multiple Dolibarr installs on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run EspoCRM on Docker Source: https://laradock.io/docs/espocrm-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is EspoCRM? [EspoCRM](https://www.espocrm.com) is an open source customer relationship management platform with a modern, extensible interface, built for sales, support and marketing teams that want to customize entities and workflows without forking the codebase. It is a PHP application backed by a MySQL, MariaDB or PostgreSQL database, served through a web server, and installed either through a browser-based wizard or a command-line installer. ## Why run EspoCRM in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One EspoCRM instance can run on an older PHP version while another project runs the latest PHP, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for EspoCRM EspoCRM has no official Docker image on Docker Hub maintained by the core team as its primary distribution channel, so a ready-made, no-lock-in environment matters even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run EspoCRM today, add a Laravel API, a WordPress marketing site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus a single-purpose image with a narrow set of tags. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for EspoCRM it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB/PostgreSQL already wired, and a `workspace` container with Composer and git installed. ## Run EspoCRM on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-espocrm-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No EspoCRM files yet? Clone Laradock first, then download and extract the EspoCRM package from the workspace container in the next steps.) ### 2. Pick the services your instance needs EspoCRM needs a web server and a database. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB or PostgreSQL instead? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point EspoCRM at the containers EspoCRM's installer asks for these values in the browser (or as flags to its CLI installer); use the service name as the database host: ``` Host Name: mysql Database Name: default User Name: default Password: secret ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, place the EspoCRM files in your project's web root (download the archive from [espocrm.com](https://www.espocrm.com) and extract it if you have not already): ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash composer install --no-dev ``` Then open [http://localhost](http://localhost) and follow EspoCRM's install wizard: it checks PHP extensions, asks for the database details from the step above, and creates the admin account. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current EspoCRM releases need PHP 8.3 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older EspoCRM instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your instance live When your EspoCRM instance is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or MySQL to run EspoCRM with Laradock? No. Everything lives inside the containers. PHP, its required extensions, and the database server are all provided; you never install them on your host. ### Which services should I start for a typical EspoCRM instance? `nginx mysql workspace` covers most instances: web server, database, and a shell. Swap `mysql` for `mariadb` or `postgres` if you prefer. ### Does EspoCRM need any special PHP settings? EspoCRM's own docs recommend `memory_limit = 256M`, plus a generous `max_execution_time` and upload limits, similar to most PHP applications with an admin UI and file imports. Edit the `memory_limit` line in `php-fpm/php8.3.ini` (or whichever `php-fpm/phpX.Y.ini` matches your `PHP_VERSION`) before installing if the defaults feel tight. ### Can I run multiple EspoCRM instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Firefly III on Docker Source: https://laradock.io/docs/firefly-iii-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Firefly III? [Firefly III](https://www.firefly-iii.org) is a free, open-source personal finance manager: it tracks income and expenses, budgets, bills and multi-currency accounts, and gives you reports and charts over all of it. Under the hood it is a Laravel application, so like any Laravel app it needs a web server, a PHP runtime, and a database (MySQL/MariaDB, PostgreSQL or SQLite); Redis is optional for cache and queues. ## Why run Firefly III in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, a database) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. Firefly III also has real PHP version requirements (the latest releases need PHP 8.5), so a container that already ships the right version saves you from upgrading your whole machine's PHP just for one app. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Firefly III Firefly III has its own official Docker image and docker-compose setup, published and maintained by its author, and for a single, standalone install that is a perfectly good choice. Laradock is still worth considering, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Firefly III today, add a Laravel API, a WordPress site, or any other PHP app beside it tomorrow, all in the same environment with the same commands, instead of juggling a separate compose file per app. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so you are not tied to whatever version the official image happens to ship. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For Firefly III, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL/MariaDB or PostgreSQL, and a `workspace` container with Composer, Node, npm, git and Artisan already installed, since Firefly III is built and installed like any other Laravel application. ## Run Firefly III on Docker with Laradock ### 1. Add Laradock to your project ```bash git clone https://github.com/firefly-iii/firefly-iii.git my-firefly-iii cd my-firefly-iii git clone https://github.com/laradock/laradock.git cd laradock ``` ### 2. Pick the services Firefly III needs Firefly III needs exactly two things: a web server and a database. Out of the box it uses the database for cache and runs jobs synchronously, so this is the whole required stack (Redis is an optional upgrade, wired below). The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Firefly III at the containers Copy `.env.example` to `.env` inside the Firefly III source and set the database connection to the service names as hostnames: ```env APP_KEY= DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` `APP_KEY` must be a random 32-character string (Firefly III's own docs recommend avoiding `=` and `#` in it); generate one and paste it in. The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins), and keep the two files in sync. ### 4. Install and run Enter the `workspace` container, where Composer, Node and Artisan live, and run Firefly III's install steps: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then, inside the container: ```bash composer install --no-dev php artisan migrate --seed php artisan firefly-iii:upgrade-database php artisan firefly-iii:laravel-passport-keys ``` Then open [http://localhost](http://localhost) and register the first user, who becomes the site owner. ## Add Redis for cache and queues (optional) Firefly III runs fine on the database for cache and processes jobs inline, so Redis is not required to boot. On a heavily-used install it is faster to cache in memory and push slow work (like importing transactions) onto a background queue. Wiring it up is two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point Firefly III at it in the app's `.env`: ```env CACHE_DRIVER=redis QUEUE_CONNECTION=redis REDIS_HOST=redis REDIS_PORT=6379 ``` If you set `QUEUE_CONNECTION=redis`, run a worker from the `workspace` container so queued jobs actually process: `php artisan queue:work`. Without those lines Firefly III ignores the Redis container entirely, which is why the required stack above leaves it out. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Recent Firefly III releases require PHP 8.5; older releases run on earlier versions. Set whichever your Firefly III version needs in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.5 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` That means you can pin an older Firefly III release to an older PHP version, or move straight to what the latest release requires, without touching anything installed on your machine. ## Take your install live When your Firefly III install is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, Composer or a database engine to run Firefly III with Laradock? No. Everything lives inside the containers. Composer, Node, npm, git and PHP are all in the `workspace` container; you never install them on your host. ### Should I use the official Firefly III Docker image instead? If you only ever plan to run Firefly III alone, the official image is a fine, well-maintained choice. Reach for Laradock when you want Firefly III alongside other PHP apps in one consistent, fully inspectable environment, or when you need a PHP version the official image does not ship. ### Which services should I start for Firefly III? `nginx mysql workspace` is all Firefly III requires: web server, database, and a shell. Swap `mysql` for `postgres` if you prefer PostgreSQL. Add `redis` only if you wire it up for [cache and queues](#add-redis-for-cache-and-queues-optional); without that config Firefly III does not touch it. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot for `vendor/`-heavy apps); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Flarum on Docker Source: https://laradock.io/docs/flarum-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Flarum? [Flarum](https://flarum.org) is a modern, fast forum platform built around a single extension system: everything from the core discussion view to third-party features is an extension, installed and updated through Composer. It is a PHP application backed by a MySQL or MariaDB database, served through a web server, and it needs Composer available on the server for both the initial install and every extension you add later. Bigger communities also lean on a queue worker, the task scheduler, and an external search engine, all of which Flarum supports through extensions. ## Why run Flarum in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP, Composer and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Flarum install can run the newer PHP its latest release requires while another project stays on an older version, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Flarum Flarum has no official Docker image of its own, only community-maintained ones, so a ready-made, no-lock-in environment matters even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your Flarum forum today, add a Laravel API, a WordPress marketing site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so a Flarum 1.x install and the newer PHP-8.3-only Flarum 2.0 can each get exactly the runtime they need. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Flarum it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB already wired, and a `workspace` container with Composer and git already installed, exactly what Flarum's own install docs assume you have. When your forum grows, Redis, Meilisearch, a mail catcher and a queue worker are each one command away. ## Run Flarum on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-flarum-forum git clone https://github.com/laradock/laradock.git cd laradock ``` (No Flarum files yet? Clone Laradock first, then create the Flarum project from the `workspace` container in the next steps.) ### 2. Pick the services your forum needs Flarum needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis or a search server to get running?** No. A fresh Flarum forum runs perfectly on `nginx mysql workspace`, using its built-in database search and running jobs synchronously. Redis, Meilisearch and a queue worker are opt-in upgrades for busier communities, wired up in their own sections below. ### 3. Point Flarum at the containers Flarum's installer writes a `config.php` for you, but this is the shape of it once installed; use the service name as the database host: ```php 'database' => [ 'driver' => 'mysql', 'host' => 'mysql', 'database' => 'default', 'username' => 'default', 'password' => 'secret', 'prefix' => '', ], ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your forum Enter the `workspace` container, use Composer to fetch Flarum, then finish the setup in the browser: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash composer create-project flarum/flarum . --stability=beta ``` Then open [http://localhost](http://localhost) and follow Flarum's install wizard: it validates your PHP extensions, asks for the database details from the step above, and creates the administrator account. That is a full Flarum forum running on Docker. ## Create the first admin account You have two ways to create that first administrator: - **Browser wizard.** The default. Open [http://localhost](http://localhost) after `composer create-project`, fill in the forum title, the database details from step 3, and your admin username, email and password. Submit, then log in at [http://localhost/login](http://localhost/login) and open **Administration** from your profile menu. - **CLI install.** From the `workspace` container, `php flarum install` runs the same setup as a series of prompts (or unattended from a config file), which is handy for scripting a fresh environment. It writes `config.php` and seeds the admin account without touching the browser. If you ever lock yourself out, `php flarum` has no built-in password reset, but you can promote any user to admin directly, or create a fresh admin, with the [FoF console commands](https://github.com/FriendsOfFlarum/console) extension or a quick SQL update on the `users` and `group_user` tables in the `mysql` container. ## Manage Flarum from the workspace Everything Flarum does on the command line runs from inside the `workspace` container, where PHP and Composer live. Enter it once: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then the `flarum` console tool handles the common jobs: ```bash php flarum info # version, PHP, enabled extensions, drivers in use php flarum cache:clear # clear the cache after any config or extension change php flarum migrate # apply pending database migrations php flarum schedule:run # run any due scheduled tasks once php flarum queue:work # process queued jobs php flarum assets:publish # re-publish core and extension assets ``` `php flarum cache:clear` is the one you will reach for most: run it after editing `config.php`, after enabling or updating an extension, or any time the forum looks stale. ## Install and update extensions Flarum is almost entirely extensions, and every one is a Composer package, so the `workspace` container is where you add them. To install an extension, require it, clear the cache, then enable it in **Administration β†’ Extensions** (or from the CLI): ```bash composer require fof/upload # example extension php flarum cache:clear php flarum migrate # only extensions that add tables need this ``` To update everything to the latest compatible versions later: ```bash composer update php flarum migrate php flarum cache:clear ``` Because Composer runs inside the container, you never install PHP or Composer on your host, and the exact same commands work on macOS, Windows and Linux. ## Add Redis for caching and queues (optional) Redis is not required, but on a busy forum it speeds up the cache and, together with a queue worker, moves slow work (emails, search indexing, notifications) off the web request. Flarum wires Redis through a local extender, so it is three steps. 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Install the [Blomstra Redis](https://github.com/blomstra/flarum-redis) package and register it in a local extender. From the `workspace` container: ```bash composer require blomstra/redis ``` Then create or edit `extend.php` in your Flarum project root, using the Laradock service name `redis` as the host: ```php 'redis', 'password' => null, 'port' => 6379, 'database' => 1, ]))->cache()->session()->queue(), ]; ``` 3. Clear the cache so Flarum picks up the new drivers: ```bash php flarum cache:clear ``` That's it: Flarum now stores its cache and session in Redis and pushes jobs onto a Redis queue. Without those steps the container just sits idle, which is why the required stack above leaves it out. On smaller sites that want a queue without running Redis, the [database queue](https://github.com/blomstra/flarum-ext-database-queue) extension is a drop-in alternative that uses your existing MySQL container. ## Run a background queue worker Once a queue driver is enabled (Redis or the database queue above), a worker process actually drains the jobs. Start it from the `workspace` container: ```bash php flarum queue:work ``` That command runs in the foreground and keeps processing jobs until you stop it. For day-to-day development, leaving it open in a second `workspace` shell is fine. To keep it alive unattended, run it under a process manager, Laradock ships a `php-worker` container backed by Supervisor for exactly this; point a program entry at `php /var/www/flarum queue:work` and it restarts the worker automatically. Remember to restart the worker after deploying code, since a long-running PHP process holds the old code in memory. ## Schedule recurring tasks with cron Many extensions rely on Flarum's scheduler for things like posting scheduled drafts, cleaning up data, or generating sitemaps. The scheduler is driven by one command that must run every minute: ```bash php flarum schedule:run ``` Laradock's `workspace` container already has cron installed and reads job files from `workspace/crontab/`. Edit `workspace/crontab/laradock` and point the entry at Flarum (the project is mounted at `/var/www`): ```cron * * * * * laradock /usr/bin/php /var/www/flarum schedule:run >> /dev/null 2>&1 ``` Rebuild the workspace so the new crontab is baked in: ```bash ./laradock rebuild workspace ``` ```bash docker compose build workspace ``` If none of your extensions use scheduled jobs, you can skip this entirely; core Flarum runs fine without it. ## Add full-text search with Meilisearch (optional) Flarum ships with database-backed search that is fine for small and medium forums. When your community grows and you want fast, typo-tolerant full-text search, swap in a real search engine. The [Scout Search](https://github.com/clarkwinkelmann/flarum-ext-scout) extension drives [Meilisearch](https://www.meilisearch.com/), which Laradock includes. 1. Start Meilisearch: ```bash ./laradock start meilisearch ``` ```bash docker compose up -d meilisearch ``` 2. From the `workspace` container, install the extension: ```bash composer require clarkwinkelmann/flarum-ext-scout php flarum cache:clear ``` 3. Enable **Scout Search** in **Administration β†’ Extensions**, choose the Meilisearch driver, and set the host to the container: `http://meilisearch:7700`. Then build the initial index from the `workspace` container: ```bash php flarum scout:import ``` New posts and discussions are indexed automatically from then on. Prefer Elasticsearch? Laradock also ships `elasticsearch`, paired with the [Blomstra Search](https://github.com/blomstra/flarum-ext-search) extension instead. ## Catch outgoing email with Mailpit (optional) Flarum sends email for signup confirmation, password resets and notifications, so you want to see those messages without delivering real mail during development. Mailpit captures everything in a web inbox. 1. Start Mailpit: ```bash ./laradock start mailpit ``` ```bash docker compose up -d mailpit ``` 2. In **Administration β†’ Email**, choose the **SMTP** driver and set: ```text Host: mailpit Port: 1025 Encryption: (leave blank) ``` Save, then use **Send Test Mail** to confirm. Every message Flarum sends now lands in the Mailpit inbox at [http://localhost:8025](http://localhost:8025). (Prefer MailHog? Start `mailhog` instead; the SMTP host becomes `mailhog` on the same port 1025, inbox also at [http://localhost:8025](http://localhost:8025).) ## Import an existing Flarum database Moving a live forum onto Laradock is a database restore plus the uploaded files. Put your SQL dump somewhere under your project (so it is visible inside the container), enter the `workspace` container, and load it into the `mysql` service: ```bash mysql -h mysql -u default -psecret default < backup.sql ``` Copy your old `storage/` (avatars, logs) and any upload folders into the new project, point `config.php` at the containers as in step 3, then finish with: ```bash php flarum migrate php flarum cache:clear ``` `migrate` brings the schema up to your installed Flarum version, and `cache:clear` drops any stale cached config. Your forum is now running on Docker with all its data intact. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Flarum 1.x runs on PHP 7.4 through 8.3, while Flarum 2.0 requires PHP 8.3 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Flarum 1.x forum and a Flarum 2.0 install side by side, each isolated, none of it installed on your machine. ## Take your forum live When your forum is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, Composer or MySQL to run Flarum with Laradock? No. Everything lives inside the containers. Composer, git and PHP are all provided; you never install them on your host. ### Which services should I start for a typical Flarum forum? `nginx mysql workspace` is all Flarum requires: web server, database, and a shell with Composer for installing and updating extensions. Swap `mysql` for `mariadb` if you prefer. Add `redis`, `meilisearch` or `mailpit` only when you set up the matching feature below; a fresh forum needs none of them. ### How do I run the queue worker and scheduler? Enable a queue driver (see [Add Redis](#add-redis-for-caching-and-queues-optional)) and run `php flarum queue:work` from the `workspace` container, kept alive by the `php-worker` container in production. For the scheduler, add the one-line cron entry to `workspace/crontab/laradock` and rebuild the workspace. Both are optional and only matter once an extension uses them. ### Can I run multiple Flarum forums on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run FluxBB on Docker Source: https://laradock.io/docs/fluxbb-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is FluxBB? [FluxBB](https://fluxbb.org) is a lightweight, fast PHP forum package forked from PunBB in 2008, built around a small footprint and a simple admin panel rather than a large extension ecosystem. It is a PHP application backed by a database (MySQL, PostgreSQL or SQLite), served through a web server, and installed through a browser-based setup wizard. The official project has been dormant since around 2021 (its site went offline and the domain lapsed), though a community-maintained fork keeps it working on current PHP versions; if you pick FluxBB today, use that fork rather than the last official release. ## Why run FluxBB in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One forum can run an older PHP version to match a legacy FluxBB install, while another project runs the latest PHP a maintained fork supports, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for FluxBB FluxBB has no official Docker image or first-party runtime of its own, so a ready-made, no-lock-in environment matters even more, especially given the project's unclear maintenance status. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your FluxBB forum today, add a Laravel API, a WordPress marketing site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so you can pin the exact PHP version an old FluxBB install or its community fork needs, without touching anything else on your machine. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for FluxBB it gives you a production-style NGINX + PHP-FPM stack, MySQL/PostgreSQL already wired, and a `workspace` container with git and the file tools you need to unpack the FluxBB package. ## Run FluxBB on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-fluxbb-forum git clone https://github.com/laradock/laradock.git cd laradock ``` (No FluxBB files yet? Clone Laradock first, then download and extract the FluxBB package from the `workspace` container in the next steps.) ### 2. Pick the services your forum needs FluxBB needs a web server and a database. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point FluxBB at the containers FluxBB's installer asks for these values in the browser and writes them into `config.php`; use the service name as the database host: ``` Database type: MySQLi Database server hostname: mysql Database username: default Database password: secret Database name: default ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your forum Enter the `workspace` container, place the FluxBB files in your project's web root (download the package from the community-maintained fork if you want current PHP support, or from [fluxbb.org](https://fluxbb.org/downloads/) for the last official release), then finish the setup in the browser: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then open `http://localhost/install.php` and follow FluxBB's install wizard: it checks your PHP version, asks for the database details from the step above, and creates the admin account. Delete `install.php` once it is done, as FluxBB's own docs recommend. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.1 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` The last official FluxBB release predates PHP 7, while the community-maintained fork runs on PHP 7.2 through 8.2; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs a legacy install pinned to an old PHP version and a fork-based install on current PHP side by side, each isolated, none of it installed on your machine. ## Take your forum live When your FluxBB forum is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or MySQL to run FluxBB with Laradock? No. Everything lives inside the containers. PHP and the database server are all provided; you never install them on your host. ### Which services should I start for a typical FluxBB forum? `nginx mysql workspace` covers most forums: web server, database, and a shell. Swap `mysql` for `postgres` if you prefer. ### Can I run multiple FluxBB forums on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run FrontAccounting on Docker Source: https://laradock.io/docs/frontaccounting-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is FrontAccounting? [FrontAccounting](https://frontaccounting.com) is an open-source, browser-based accounting and ERP application for small and medium businesses: general ledger, invoicing, inventory, banking and multi-company, multi-currency support, all in a single PHP codebase. It is a classic LAMP-style app with no build step or Node toolchain: PHP rendering pages behind a web server, backed by a MySQL database whose accounting tables need InnoDB for transactions. ## Why run FrontAccounting in Docker? Docker packages the pieces FrontAccounting needs (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One project can run the PHP version FrontAccounting was tested against while another runs something entirely different, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, InnoDB, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for FrontAccounting FrontAccounting has no official Docker image or compose file from its core team; what exists are a handful of unofficial, community-maintained images, none of them the default way to run it. That makes a ready-made, no-lock-in environment matter even more. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run FrontAccounting today, add a Laravel API, a WordPress site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so an older FrontAccounting install and a freshly upgraded one each get exactly the runtime they need. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for FrontAccounting it gives you a production-style NGINX + PHP-FPM stack, a MySQL container with InnoDB available out of the box, and a `workspace` container with git and Composer installed to fetch and unpack the source. ## Run FrontAccounting on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-frontaccounting-app git clone https://github.com/laradock/laradock.git cd laradock ``` (No FrontAccounting files yet? Clone Laradock first, then download the FrontAccounting release from the workspace container in the next steps.) ### 2. Pick the services FrontAccounting needs FrontAccounting needs a web server and a MySQL database; the web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` The full catalog of services, if you later need a mail catcher for outgoing invoices or anything else, is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point FrontAccounting at the containers FrontAccounting does not read a `.env` file; its browser-based install wizard writes the database connection into `config_db.php` for you. When the wizard asks for the database server, use the service name as the host: ```text Host: mysql Database: default User: default Password: secret ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run Enter the `workspace` container, where git and Composer live, fetch a FrontAccounting release, and make the app directory writable for the installer: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash cd www/my-frontaccounting-app # wherever nginx serves this project from # download and extract a FrontAccounting release here, then: chmod -R 777 . ``` Then open [http://localhost](http://localhost) and follow the install wizard: it creates the database schema and writes `config_db.php` and `config.php`. FrontAccounting is officially implemented and tested against MySQL, with InnoDB required for its transactional tables; the wizard will not offer PostgreSQL. Once installation finishes, tighten the permissions back down as the installer instructs. That is a full FrontAccounting install running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` The current FrontAccounting 2.4.x series is tested against PHP 8.0 through 8.5, and older instances still running on a legacy PHP build can be reproduced the same way, each isolated, none of it installed on your machine. ## Take your install live When your FrontAccounting install is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or MySQL to run FrontAccounting with Laradock? No. Everything lives inside the containers. PHP, the web server and MySQL (with InnoDB) are all provided; you never install them on your host. ### Which services should I start for FrontAccounting? `nginx mysql workspace` covers a typical install: web server, database, and a shell to fetch the source with git or Composer. ### Does FrontAccounting support PostgreSQL instead of MySQL? Officially, no. FrontAccounting is implemented and tested against MySQL, and InnoDB is required for its transactional accounting tables; other databases are not a supported configuration, so Laradock's `mysql` service is the right choice here. ### Can I run multiple FrontAccounting instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Invoice Ninja on Docker Source: https://laradock.io/docs/invoice-ninja-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Invoice Ninja? [Invoice Ninja](https://invoiceninja.com) is a source-available invoicing, quoting and payments platform built for freelancers and small businesses, on top of the Laravel framework. It is known for free self-hosting, client and vendor portals, recurring invoices, time tracking and a large list of payment gateway integrations. Being a Laravel app, it genuinely needs a web server, a PHP runtime with a fairly specific extension list, and a MySQL or PostgreSQL database. ## Why run Invoice Ninja in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. Invoice Ninja's PHP and extension requirements have shifted from release to release; a container lets you pin exactly the version a given release needs without touching anything else installed on your machine. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Invoice Ninja Invoice Ninja publishes its own official Docker images and Dockerfiles ([invoiceninja/dockerfiles](https://github.com/invoiceninja/dockerfiles), also on [Docker Hub](https://hub.docker.com/r/invoiceninja/invoiceninja)), so, like Laravel, it does not strictly need Laradock. It is still the best fit if Invoice Ninja is not the only thing you run, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress marketing site, or another PHP app beside Invoice Ninja, it runs in the same environment with the same commands. A single-purpose image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the one image and PHP version the official build ships. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For Invoice Ninja specifically, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL or PostgreSQL, and a `workspace` container with Composer, git and Artisan already installed, since Invoice Ninja is a Laravel app under the hood. ## Run Invoice Ninja on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-invoiceninja-app git clone https://github.com/laradock/laradock.git cd laradock ``` (No Invoice Ninja source yet? Clone Laradock first, then pull the Invoice Ninja source into your project directory from the workspace container in the next steps.) ### 2. Pick the services Invoice Ninja needs Invoice Ninja needs a web server and a database. The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL instead? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Invoice Ninja at the containers In your app's `.env`, use the service names as hostnames: ```env DB_CONNECTION=mysql DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your app Enter the shell where Composer, git and Artisan live, and run the usual Laravel install steps: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` ```bash composer install php artisan key:generate php artisan migrate ``` Then open [http://localhost](http://localhost) and complete the web-based `/setup` wizard to create the first account, or run `php artisan migrate:fresh --seed` beforehand if you want sample data instead. ## Add a queue worker (optional) Invoice Ninja pushes email, PDF generation and recurring-invoice jobs onto a Laravel queue. A fresh install runs fine on the synchronous default, but for anything realistic you want a background worker so those jobs do not block web requests. Two steps: 1. Point the queue at the database (or Redis, see below) in your app's `.env`: ```env QUEUE_CONNECTION=database ``` 2. Start the dedicated worker container, which runs `php artisan queue:work` for you: ```bash ./laradock start php-worker ``` ```bash docker compose up -d php-worker ``` Without a worker running, queued emails and PDFs simply wait, which is why the required stack above leaves it out. ## Add Redis (optional) Being a Laravel app, Invoice Ninja can use Redis as its cache and queue backend with no extra plugin, just config. Start the container and point the app at it: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` Then in your app's `.env`: ```env CACHE_DRIVER=redis QUEUE_CONNECTION=redis REDIS_HOST=redis ``` ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.2 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current Invoice Ninja releases require PHP 8.2 with extensions such as bcmath, gd, imagick, mbstring and zip already enabled in Laradock's PHP-FPM image; older self-hosted releases pinned to PHP 7.4 or 8.1 still run the same way, each isolated, none of it installed on your machine. ## Take your app live When your Invoice Ninja install is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, Composer or MySQL to run Invoice Ninja with Laradock? No. Everything lives inside the containers. Composer, git and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Invoice Ninja install? `nginx mysql workspace` covers most installs: web server, database, and a shell. Swap `mysql` for `postgres` if you prefer. ### Should I use Laradock or Invoice Ninja's official Docker image? The official image is fine if Invoice Ninja is the only app on the box. Reach for Laradock when you want the same environment to also run other PHP apps, need a non-default PHP version, or want every Dockerfile visible and editable. ### Can I run multiple Invoice Ninja instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Kanboard on Docker Source: https://laradock.io/docs/kanboard-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Kanboard? [Kanboard](https://kanboard.org) is an open-source kanban project management tool, known for staying deliberately simple and minimalist rather than chasing every feature a heavier tool like Jira ships. It is a PHP application served through a web server, and unlike most self-hosted PHP apps on this list, it needs almost no infrastructure to run: out of the box it stores everything in a single SQLite database file, with MySQL/MariaDB and PostgreSQL available as opt-in alternatives once a team outgrows a single file. ## Why run Kanboard in Docker? Docker packages the pieces a self-hosted app like this needs (NGINX, PHP-FPM, and a database if you add one) into isolated containers that run the same on every machine. Instead of installing PHP onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Kanboard instance can run on an older PHP version while another project runs the latest PHP, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Kanboard Kanboard does ship its own official Docker image (`kanboard/kanboard` on Docker Hub), so, unlike most PHP projects, it does not strictly need Laradock. It is still the best fit, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress site, or a plain PHP script beside your Kanboard instance, it runs in the same environment with the same commands. A single-purpose image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the narrow, pinned version the official image ships. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Kanboard it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB/PostgreSQL wired in for whenever you need them, and a `workspace` container with git and the PHP CLI to run Kanboard's maintenance commands. ## Run Kanboard on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-kanboard-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Kanboard codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services Kanboard needs Kanboard's biggest difference from the rest of this list: it needs no database service at all to start. By default it writes to a SQLite file inside its own `data/` folder, so a web server is genuinely enough: ```bash ./laradock start nginx workspace ``` ```bash cp .env.example .env docker compose up -d nginx workspace ``` Outgrowing a single SQLite file, or setting up Kanboard for a team that needs real concurrency? Add MySQL or PostgreSQL the same way you would for any other app: ```bash ./laradock start nginx mysql workspace ``` ```bash docker compose up -d nginx mysql workspace ``` The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Kanboard at the containers Kanboard reads its settings from a `config.php` file at the project root (copy `config.default.php` to get started), and every setting in that file is also readable as an environment variable of the same name. Leave `DB_DRIVER` unset and Kanboard just uses SQLite, no further config needed. To switch to MySQL/MariaDB or PostgreSQL instead, set the connection constants and point them at the service name: ```php define('DB_DRIVER', 'mysql'); define('DB_USERNAME', 'default'); define('DB_PASSWORD', 'secret'); define('DB_HOSTNAME', 'mysql'); define('DB_NAME', 'default'); ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, place the Kanboard codebase, and let the first request run the setup: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Once inside, place or clone the Kanboard codebase into the current directory. Then open [http://localhost](http://localhost) and log in with the default admin account (`admin` / `admin`), which Kanboard prompts you to change on first login. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Kanboard requires PHP 8.1 or newer since version 1.2.46; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs a Kanboard instance pinned to an older release you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your instance live When your Kanboard instance is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP to run Kanboard with Laradock? No. Everything lives inside the containers. PHP and git are reachable from the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Kanboard instance? `nginx workspace` is enough on its own, since Kanboard defaults to SQLite. Add `mysql` or `postgres` only once you need a shared, concurrent database. ### Should I use SQLite or MySQL/PostgreSQL for Kanboard? SQLite is the zero-config default and fine for a single user or a small team on a local machine. Kanboard's own docs recommend MySQL/MariaDB or PostgreSQL for larger or multi-user deployments, and specifically caution against SQLite on network filesystems; keep the `data/` folder on a local bind mount (Laradock's default) or move to MySQL/PostgreSQL once several people hit the instance at once. ### Can I run multiple Kanboard instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Koel on Docker Source: https://laradock.io/docs/koel-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Koel? [Koel](https://koel.dev) is a self-hosted personal music streaming server: point it at a folder of audio files and it scans, catalogs and streams your library back through a Vue-based web player. It is a Laravel application under the hood, so a real Koel install needs a web server, a PHP runtime and a database (MySQL, PostgreSQL, MariaDB or SQLite), plus a persistent storage path for the actual music files, kept separate from the database. ## Why run Koel in Docker? Docker packages the web server, PHP and the database into isolated containers that run the same on every machine. Instead of installing PHP and a database engine onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One project can run PHP 8.4 while another runs 8.2, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions, and a volume for your media library) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Koel Koel ships its own official Docker Compose setup (maintained by the Koel project itself, under `koel/docker`), so, like Laravel, it does not strictly need Laradock. It is still the best fit, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress blog, or a plain PHP script beside your Koel instance, it runs in the same environment with the same commands. A single-purpose compose file cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the one PHP version baked into Koel's own image. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For Koel specifically, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL/PostgreSQL, and a `workspace` container with Composer, Node, npm, git and Artisan already installed; you mount your music folder as a volume and point `MEDIA_PATH` at it. ## Run Koel on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-koel-server git clone https://github.com/laradock/laradock.git cd laradock ``` (No Koel files yet? Clone Laradock first, then clone Koel from [its GitHub repo](https://github.com/koel/koel) into your project directory.) ### 2. Pick the services your library needs Koel needs a web server, PHP and a database. Start exactly those (the web server pulls in PHP-FPM automatically): ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer PostgreSQL? Swap the name: `./laradock start nginx postgres workspace` (or `docker compose up -d nginx postgres workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Koel at the containers and your music In your app's `.env`, use the service names as hostnames, and point `MEDIA_PATH` at a mounted volume holding your audio files: ```env DB_CONNECTION=mysql DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret MEDIA_PATH=/music ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). Mount your actual music folder into the `php-fpm` and `workspace` containers at the same path so both the scanner and the player can reach it. ### 4. Install and run your library Enter the shell where Composer, npm and Artisan live: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then run Koel's own setup wizard inside that shell: ```bash composer install php artisan koel:init ``` The wizard confirms your `.env`, migrates the database, sets the media path, and creates the first admin account. Then open [http://localhost](http://localhost). That is a full Koel server running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current Koel releases require PHP 8.2 or newer, and anything up to 8.5 works, so an older Koel install and a freshly upgraded one run side by side, each isolated, none of it installed on your machine. ## Add Redis for caching and queues (optional) Koel is a Laravel app, so Redis needs no plugin or module, just switch the drivers on. On a larger library it caches metadata and moves the media scan into a background queue so the web player stays responsive. Two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point Koel at it in your app's `.env` (the service name is the host): ```env REDIS_HOST=redis CACHE_DRIVER=redis QUEUE_CONNECTION=redis ``` To actually run queued scans, start a worker from the `workspace` container: `php artisan queue:work`. Without these lines Koel runs fine synchronously, which is why the required stack above leaves Redis out. ## Take your server live When your Koel server is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP, Composer or ffmpeg to run Koel with Laradock? No. PHP, Composer, Node and npm all live inside the `workspace` container. If your library needs transcoding, you still need to make an `ffmpeg` binary available to the container and point `FFMPEG_PATH` at it. ### Which services should I start for a typical Koel server? `nginx mysql workspace` covers most installs: web server, database, and a shell for Artisan. Swap `mysql` for `postgres` if you prefer. ### Where do my actual music files live? Outside the database, on a volume you mount into the containers and point `MEDIA_PATH` at. Keep that path stable across restarts and rebuilds so Koel doesn't lose track of your library. ### Can I run multiple Koel instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Leantime on Docker Source: https://laradock.io/docs/leantime-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Leantime? [Leantime](https://leantime.io) is an open source project management system built for goal-driven teams rather than career project managers, with task boards, milestones, and goal tracking designed with ADHD, autism and dyslexia in mind. A Leantime instance is a PHP application (its own lightweight framework, not Laravel) backed by MySQL or MariaDB, served through a web server, with a browser-based `/install` wizard handling setup once the database connection is configured. ## Why run Leantime in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Leantime instance can run on a specific PHP version while another project runs a different one, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Leantime Leantime does ship its own official Docker image (`leantime/leantime` on Docker Hub, maintained by the Leantime team), and that image expects an external MySQL database anyway, so it does not strictly need Laradock. It is still worth considering, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress site, or a plain PHP script beside your Leantime instance, it runs in the same environment with the same commands. A single-purpose image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the narrow set of tags the official image ships. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Leantime it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB already wired (Leantime needs the database to exist externally either way), and a `workspace` container with git and the PHP CLI available. ## Run Leantime on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-leantime-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Leantime codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs Leantime needs a web server and a database (it will not run without one). The web server pulls in PHP-FPM automatically: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB instead? Swap the name: `./laradock start nginx mariadb workspace`. The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Leantime at the containers Copy Leantime's `config/sample.env` to `config/.env` and use the service name as the host: ```env LEAN_DB_HOST=mysql LEAN_DB_DATABASE=default LEAN_DB_USER=default LEAN_DB_PASSWORD=secret LEAN_DB_PORT=3306 ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, place or clone the Leantime codebase, and set the `.env` values above: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Once inside, run: ```bash git clone https://github.com/Leantime/leantime.git --single-branch . # only if you have no codebase yet cp config/sample.env config/.env # edit config/.env with the LEAN_DB_* values above ``` Then open [http://localhost/install](http://localhost/install) and complete Leantime's setup wizard, which finishes the database migration and creates your admin account. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Leantime requires PHP 8.2 or newer for current production releases; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Leantime instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your instance live When your Leantime instance is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or MySQL to run Leantime with Laradock? No. Everything lives inside the containers. PHP and git are reachable from the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Leantime instance? `nginx mysql workspace` covers it: web server, database, and a shell. Swap `mysql` for `mariadb` if you prefer. ### Can I run multiple Leantime instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot for `vendor/`-heavy apps); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run LinkAce on Docker Source: https://laradock.io/docs/linkace-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is LinkAce? [LinkAce](https://www.linkace.org) is a self-hosted bookmark manager for archiving and organizing links, tags, lists and notes instead of relying on a browser's bookmark bar. It is a Laravel application, so a real LinkAce install needs a web server, a PHP runtime, a MySQL or MariaDB database, and a `queue`/scheduler process for background jobs like link archiving. ## Why run LinkAce in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One project can run PHP 8.4 while another runs 8.2, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for LinkAce LinkAce ships its own official Docker image (`linkace/linkace` on Docker Hub, maintained by its creator), so, like Laravel, it does not strictly need Laradock. It is still the best fit, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a WordPress site, a plain PHP script, or another Laravel app beside your LinkAce instance, it runs in the same environment with the same commands. A single-purpose image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the one PHP version baked into LinkAce's own image. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For LinkAce specifically, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL/MariaDB, and a `workspace` container with Composer, Node, npm, git and Artisan already installed. ## Run LinkAce on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-linkace-app git clone https://github.com/laradock/laradock.git cd laradock ``` (No LinkAce files yet? Clone Laradock first, then clone LinkAce from [its GitHub repo](https://github.com/Kovah/LinkAce) into your project directory.) ### 2. Pick the services your bookmarks need LinkAce needs a web server, PHP and a database. Start exactly those (the web server pulls in PHP-FPM automatically): ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB over MySQL? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point LinkAce at the containers In your app's `.env`, use the service names as hostnames: ```env DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your bookmarks Enter the shell where Composer, npm and Artisan live: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then run LinkAce's own setup commands inside that shell: ```bash composer install php artisan key:generate php artisan migrate php artisan setup:complete php artisan registeruser --admin ``` Then open [http://localhost](http://localhost). That is a full LinkAce install running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.4 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current LinkAce releases require PHP 8.2 or newer, and anything up to 8.5 works, so the same tool runs an older LinkAce install pinned to 8.2 and a freshly upgraded one side by side, each isolated, none of it installed on your machine. ## Run background jobs (optional) LinkAce is a Laravel app, so its background work (link archiving, broken-link checks, scheduled tasks) runs through Laravel's queue and scheduler. A fresh install works without them, but archiving and periodic checks only fire once a worker is running. From the `workspace` container: ```bash php artisan queue:work # process archiving and check jobs php artisan schedule:work # run the periodic broken-link checks ``` For a heavier setup, back the queue with Redis. Start it and switch the driver in your app's `.env`: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` ```env REDIS_HOST=redis QUEUE_CONNECTION=redis ``` Because LinkAce boots and serves bookmarks without a worker, the required stack above leaves these out. ## Take your app live When your LinkAce install is ready, the same Laradock stack becomes your deployment. You build one hardened image and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run LinkAce with Laradock? No. Everything lives inside the containers. Composer, Node, npm, git and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical LinkAce install? `nginx mysql workspace` covers most installs: web server, database, and a shell for Artisan. Swap `mysql` for `mariadb` if you prefer. ### Can I run multiple LinkAce instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop; it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Lychee on Docker Source: https://laradock.io/docs/lychee-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Lychee? [Lychee](https://lycheeorg.dev) is a self-hosted photo management app: upload, organize into albums, and share your photos from your own server instead of a third-party cloud. It is a Laravel application, so a real Lychee install needs a web server, a PHP runtime, a database (MySQL, MariaDB, PostgreSQL or SQLite), and a persistent storage path for the uploaded photos themselves, kept separate from the database. ## Why run Lychee in Docker? Docker packages the web server, PHP and the database into isolated containers that run the same on every machine. Instead of installing PHP and a database engine onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One project can run PHP 8.4 while another runs 8.2, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions, and a volume for your photo library) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Lychee Lychee ships its own official Docker image (`lycheeorg/lychee`, maintained by the Lychee project), so, like Laravel, it does not strictly need Laradock. It is still the best fit, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress blog, or a plain PHP script beside your Lychee gallery, it runs in the same environment with the same commands. A single-purpose image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the one PHP version baked into Lychee's own image. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. For Lychee specifically, Laradock wires a production-style NGINX + PHP-FPM stack, MySQL/MariaDB, and a `workspace` container with Composer, Node, npm, git and Artisan already installed; you mount a photo storage folder as a volume so your library survives rebuilds. ## Run Lychee on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-lychee-gallery git clone https://github.com/laradock/laradock.git cd laradock ``` (No Lychee files yet? Clone Laradock first, then clone Lychee from [its GitHub repo](https://github.com/LycheeOrg/Lychee) into your project directory.) ### 2. Pick the services your gallery needs Lychee needs a web server, PHP and a database. Start exactly those (the web server pulls in PHP-FPM automatically): ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB or PostgreSQL? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. ### 3. Point Lychee at the containers and your photos In your app's `.env`, use the service names as hostnames: ```env DB_CONNECTION=mysql DB_HOST=mysql DB_DATABASE=default DB_USERNAME=default DB_PASSWORD=secret ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). Mount a dedicated folder into the `php-fpm` and `workspace` containers for `public/uploads` so your photos persist outside the container. ### 4. Install and run your gallery Enter the shell where Composer, npm and Artisan live: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then install dependencies and run the database migrations: ```bash composer install --no-dev php artisan key:generate php artisan migrate ``` Then open [http://localhost](http://localhost) and finish setup (creating the first admin account) in the browser. That is a full Lychee install running on Docker. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current Lychee releases require PHP 8.2 or newer, and anything up to 8.5 works, so an older Lychee install and a freshly upgraded one run side by side, each isolated, none of it installed on your machine. ## Take your gallery live When your gallery is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. Keep your photo storage volume mounted on the production host so your library persists across deploys. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run Lychee with Laradock? No. Everything lives inside the containers. Composer, Node, npm and Artisan are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Lychee install? `nginx mysql workspace` covers most installs: web server, database, and a shell for Artisan. Swap `mysql` for `mariadb` or `postgres` if you prefer. ### Where do my actual photos live? Outside the database, on a volume mounted into the containers at Lychee's uploads path. Keep that volume across rebuilds so your library isn't lost. ### Can I run multiple Lychee instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Matomo on Docker Source: https://laradock.io/docs/matomo-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Matomo? [Matomo](https://matomo.org) (formerly Piwik) is a self-hosted, privacy-focused web analytics platform, an open-source alternative to Google Analytics that keeps all visitor data on your own server. It is a PHP application backed by a MySQL or MariaDB database, served through a web server. Two things make it different from a plain CMS: it wants a recurring cron job that archives report data (so dashboards load fast), and it wants a comfortable PHP `memory_limit` once you are tracking sites with real traffic. Everything else, high-traffic request queuing, scheduled email reports, log import, is optional and layered on when you need it. ## Why run Matomo in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Matomo install can run the latest PHP recommended for performance while another project runs an older version it still depends on, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Matomo Matomo does maintain its own official Docker images ([matomo-org/docker](https://github.com/matomo-org/docker), also published as a [Docker Official Image](https://hub.docker.com/_/matomo)), so, unlike most self-hosted PHP apps, it does not strictly need Laradock. It is still the best fit for anyone running more than just Matomo, and here is why: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. The day you add a Laravel API, a WordPress marketing site, or a plain PHP script beside your analytics install, it runs in the same environment with the same commands. A single-purpose Matomo image cannot do that. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, versus the fixed image variants a purpose-built container gives you. Redis for high-traffic tracking and a mail catcher for scheduled reports are each one command away. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Matomo it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB already wired, and a `workspace` container with git and PHP's CLI (for the install, update, and archiving commands) installed. ## Run Matomo on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-matomo-install git clone https://github.com/laradock/laradock.git cd laradock ``` (No Matomo files yet? Clone Laradock first, then download the Matomo package from the `workspace` container in the next steps.) ### 2. Pick the services your install needs Matomo needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis?** Not to get running. A normal Matomo install writes tracking requests straight to MySQL and needs nothing else. Redis only helps once you are ingesting very high traffic and add the QueuedTracking plugin. See [Add Redis for high-traffic tracking](#add-redis-for-high-traffic-tracking-optional) below when you actually need it. ### 3. Point Matomo at the containers Matomo's installer asks for these values in the browser and writes them into `config/config.ini.php`; use the service name as the database host: ``` Database Server: mysql Login: default Password: secret Database Name: default ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, where git and PHP's CLI live, place the Matomo files in your project's web root (download the package from [matomo.org](https://matomo.org/download/) and extract it if you have not already), then finish the setup in the browser: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Then open [http://localhost](http://localhost) and follow Matomo's install wizard: system check, database connection (the values above), table creation, Super User account, and your first website plus its tracking code. There is no built-in, fully headless CLI equivalent to this wizard; if you need an unattended install, either pre-fill `config/config.ini.php` with your database details before the first request (Matomo then skips the database step), or use the community [ExtraTools plugin](https://plugins.matomo.org/ExtraTools), which adds a `matomo:install` console command. The account you create in that wizard is your **Super User** (Matomo's admin). If you ever lose the password, use the "Lost your password?" link on the login screen once a mail service is wired up (see [Add a mail catcher](#add-a-mail-catcher-for-scheduled-reports-and-alerts-optional) for local mail, or your real SMTP host in production). ## Set up report archiving (the one cron Matomo needs) This is the step people miss. By default Matomo archives reports on the fly when someone opens a dashboard, which gets slow fast. The project's strong recommendation is to **turn browser archiving off and run the archiver on a schedule** instead. First, in Matomo go to **Administration -> System -> General Settings** and set "Archive reports when viewed from the browser" to **No**. Then run the archiver from the `workspace` container. The console is a script named `console` in your Matomo root (adjust the path to wherever your Matomo files live, `/var/www` is the mounted project root): ```bash php /var/www/console core:archive --url=http://localhost/ ``` To run it automatically every hour, add a single line to your host machine's crontab (`crontab -e`) that calls into the running `workspace` container: ```cron 5 * * * * cd /path/to/laradock && docker compose exec -T workspace php /var/www/console core:archive --url=http://localhost/ > /dev/null 2>&1 ``` The `-T` disables the pseudo-TTY so cron can run it non-interactively. In production you point `--url` at your real domain and schedule the same command; see [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production). ## Add Redis for high-traffic tracking (optional) A normal install writes every tracking request directly to MySQL, which is fine for most sites. Once you are handling hundreds of requests per second, that write becomes the bottleneck. Matomo's [QueuedTracking](https://plugins.matomo.org/QueuedTracking) plugin fixes this by pushing raw tracking requests into **Redis** (a write of a few milliseconds) and draining the queue into MySQL in the background. Wiring it up: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. From the `workspace` container, install and enable the plugin: ```bash php /var/www/console plugin:activate QueuedTracking ``` 3. In the Matomo admin, go to **Administration -> System -> General Settings -> Queued Tracking** and set the backend to **Redis** with host `redis` and port `6379` (the Laradock service name and default port). Choose the number of workers based on your traffic. 4. Drain the queue on a schedule. Add another host crontab line so it runs every minute: ```cron * * * * * cd /path/to/laradock && docker compose exec -T workspace php /var/www/console queuedtracking:process --no-ansi > /dev/null 2>&1 ``` Check queue depth any time with `php /var/www/console queuedtracking:monitor`. Without those steps the Redis container just sits idle, which is why the required stack above leaves it out. ## Add a mail catcher for scheduled reports and alerts (optional) Matomo can email scheduled PDF/HTML reports, custom alerts, and password-reset links, all of which need an SMTP server. For local development, Laradock ships a mail catcher that traps every outgoing message in a web inbox so nothing leaves your machine: ```bash ./laradock start mailhog ``` ```bash docker compose up -d mailhog ``` Then in Matomo go to **Administration -> System -> General Settings -> Email server settings**, choose SMTP, and enter: ``` SMTP server: mailhog Port: 1025 Authentication: none Encryption: none ``` Open [http://localhost:8025](http://localhost:8025) to read whatever Matomo sends. Now "Email Reports", alert notifications, and the "Lost your password?" flow all work locally. In production you swap these for your real mail provider's SMTP credentials. ## Import existing server logs (optional) Matomo can build reports from raw web-server access logs instead of (or in addition to) the JavaScript tracker, which is handy for back-filling history or tracking things JavaScript cannot see. The importer is a Python script shipped inside Matomo at `misc/log-analytics/import_logs.py`, and the `workspace` container already has Python. From inside `workspace`: ```bash python3 /var/www/misc/log-analytics/import_logs.py \ --url=http://localhost/ \ --idsite=1 \ /path/to/access.log ``` Point `/path/to/access.log` at a log file you have mounted into the project, set `--idsite` to the website ID you are importing into, and Matomo parses each line into visits. Combine it with the archiving cron above so the imported data shows up in your reports. ## Everyday admin from the console Matomo's `console` command is the CLI for almost every maintenance task. Run these from inside the `workspace` container (`./laradock workspace`), pointing at your Matomo root: ```bash php /var/www/console list # every available command php /var/www/console core:update # apply DB migrations after updating files php /var/www/console core:clear-caches # clear Matomo's caches php /var/www/console core:invalidate-report-data # force specific reports to re-archive php /var/www/console plugin:list # see installed plugins ``` After you replace the Matomo files with a newer release, always run `core:update` (or click through the updater in the browser) so the database schema catches up. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Matomo works down to PHP 7.2.5 but is markedly faster on current PHP 8.x, which is what the project recommends; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Matomo install and a brand-new one side by side, each isolated, none of it installed on your machine. Tracking a busy site? Give PHP more headroom by raising `PHP_FPM_INSTALL_...` limits or the `memory_limit` in `php-fpm/php.ini` and `workspace`, then rebuild the same way. Archiving large sites is the main reason Matomo wants a generous `memory_limit`. ## Import an existing Matomo database Moving an install from another host is just a database restore plus the files. Copy your existing Matomo directory into the project web root, drop your SQL dump into the project (Laradock mounts it into `workspace`), then from inside `workspace`: ```bash mysql -u default -psecret -h mysql default < backup.sql ``` Update `config/config.ini.php` so the `[database]` `host` is `mysql` (and the `login`/`password`/`dbname` match the values in step 3), open the site, and run `php /var/www/console core:update` if the dump came from an older Matomo version. Your dashboards, websites, and users come across intact. ## Track multiple websites A single Matomo install already tracks any number of separate websites, each with its own tracking code and its own `idsite`. You do not run one container per site: add each site under **Administration -> Websites -> Manage**, drop the generated snippet on that site, and they all report into the same dashboard. Only spin up a second Laradock (see the FAQ) when you want a fully independent Matomo instance on a different PHP version. ## Take your install live When your Matomo install is ready, the same Laradock stack becomes your deployment. You build one hardened image of the app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. Remember to schedule the archiving cron on the live host exactly as shown above. ## Frequently Asked Questions ### Do I need to install PHP or MySQL to run Matomo with Laradock? No. Everything lives inside the containers. PHP, its required extensions (curl, gd, mbstring, xml among them), and the database server are all provided; you never install them on your host. ### Which services should I start for a typical Matomo install? `nginx mysql workspace` is all Matomo requires: web server, database, and a shell. Swap `mysql` for `mariadb` if you prefer. Add `redis` only for the high-traffic [QueuedTracking](#add-redis-for-high-traffic-tracking-optional) setup, and `mailhog` only when you want [scheduled email reports](#add-a-mail-catcher-for-scheduled-reports-and-alerts-optional); neither is needed for a normal install. ### How do I keep report dashboards fast? Turn off browser-triggered archiving and run `core:archive` on a schedule. See [Set up report archiving](#set-up-report-archiving-the-one-cron-matomo-needs) above; it is the single most important step for a responsive Matomo. ### Can I run multiple Matomo instances on different PHP versions? Yes. One Matomo already tracks many websites, but for a fully separate instance give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Does this work the same on macOS, Windows and Linux? Yes. Laradock runs anywhere Docker runs. On macOS/Windows, file-sync speed depends on Docker Desktop (VirtioFS helps a lot); it is a Docker Desktop trait, not specific to Laradock. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps, and remember to schedule Matomo's archiving cron the same way you would locally. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run Mautic on Docker Source: https://laradock.io/docs/mautic-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is Mautic? [Mautic](https://www.mautic.org) is an open source marketing automation platform for email campaigns, landing pages, forms, lead scoring and segmentation, built on the Symfony framework. A Mautic instance is a PHP application backed by MySQL or MariaDB and served through a web server. What makes it different from a plain CRUD app is that most of its real work happens outside the web request: segment updates, campaign triggers and email sends are console commands that must run on a schedule (cron), and from Mautic 5 outbound email is processed through a Symfony Messenger queue. So the two things Mautic truly needs to function are a database and a scheduler, and that is exactly what the stack below sets up. ## Why run Mautic in Docker? Docker packages each of those pieces (NGINX, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between projects and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One Mautic instance can run on a specific PHP version while another project runs a different one, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions, cron) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for Mautic Mautic has no official Docker image maintained by the Mautic project itself; the closest options are community-maintained images you still have to wire and trust. Here is why Laradock is the best fit: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run Mautic today, add a Laravel API or a WordPress marketing site beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so Mautic gets exactly the runtime and extensions its current release needs, plus RabbitMQ, a mail catcher and a worker container one command away when a campaign send grows. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit, which matters when you need to tune PHP's `max_execution_time` or memory limit for a large campaign send. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production and to every other project. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for Mautic it gives you a production-style NGINX + PHP-FPM stack, MySQL/MariaDB already wired, and a `workspace` container with Composer, Node, git and the Symfony console, from which you run the installer and the cron commands campaign processing depends on. The scheduler and the email queue still need wiring, and the sections below show exactly how. ## Run Mautic on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-mautic-instance git clone https://github.com/laradock/laradock.git cd laradock ``` (No Mautic codebase yet? Clone Laradock first, then pull one down from the workspace container in the next steps.) ### 2. Pick the services your instance needs Mautic needs exactly two things to boot: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start nginx mysql workspace ``` ```bash cp .env.example .env docker compose up -d nginx mysql workspace ``` Prefer MariaDB instead? Swap the name: `./laradock start nginx mariadb workspace` (or `docker compose up -d nginx mariadb workspace`). The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **What about the queue and cron?** They do not need extra containers. Cron runs inside the `workspace` container you already started, and Mautic's email queue defaults to the database, so `nginx mysql workspace` is enough to run everything. Add [RabbitMQ](#move-the-email-queue-to-rabbitmq-optional) or a [mail catcher](#catch-outgoing-email-locally-optional) only when you specifically want them. ### 3. Point Mautic at the containers Mautic's CLI installer takes the database connection as flags and writes them into its configuration file (`config/local.php` on Mautic 5, `app/config/local.php` on Mautic 4 and earlier). Use the service name as the host: ```bash php bin/console mautic:install --force \ https://localhost \ --db_driver=pdo_mysql --db_host=mysql --db_port=3306 --db_name=default \ --db_user=default --db_password=secret \ --admin_email=you@example.com --admin_password=secret ``` The default database, user and password live in Laradock's `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your instance Enter the `workspace` container, where Composer, Node and the Symfony console live, place or clone the Mautic codebase, then run the installer: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` Once inside: ```bash composer install php bin/console mautic:install --force https://localhost \ --db_driver=pdo_mysql --db_host=mysql --db_port=3306 --db_name=default \ --db_user=default --db_password=secret \ --admin_email=you@example.com --admin_password=secret ``` Then open [http://localhost](http://localhost) and log in with the admin email and password you passed above. That is a full Mautic instance running on Docker. Before Mautic actually processes anything, wire up the scheduler in the next section: without it, segments never refresh and campaigns never fire. ## Keep Mautic running: cron and the scheduler This is not optional for a working Mautic. Segment membership, campaign steps and scheduled sends are all console commands; nothing happens just because someone visits the site. Run these from inside the `workspace` container (paths are relative to your Mautic root): ```cron */15 * * * * php bin/console mautic:segments:update */15 * * * * php bin/console mautic:campaigns:update */15 * * * * php bin/console mautic:campaigns:trigger */15 * * * * php bin/console mautic:messages:send ``` Stagger them by a minute or two rather than firing all at once. On Mautic 5 the old `mautic:emails:send` command is gone: outbound email now flows through the queue described in the next section. You have two ways to schedule them with Laradock: 1. **Inside the workspace container.** Enable the built-in cron by setting `WORKSPACE_INSTALL_CRON=true` in Laradock's `.env`, rebuild the workspace, then add the lines above to its crontab (`crontab -e` from inside the container). 2. **A dedicated scheduler service.** Start Laradock's `cron` container and put the same entries there, keeping scheduling out of the shell container. ```bash ./laradock rebuild workspace # after setting WORKSPACE_INSTALL_CRON=true ``` ```bash docker compose build workspace # after setting WORKSPACE_INSTALL_CRON=true ``` ## Process outgoing email (the queue) From Mautic 5, email is sent through a Symfony Messenger queue rather than a direct cron command. Out of the box Mautic uses the **database (Doctrine) transport**, so no extra container is required: the messages sit in a `messenger_messages` table and a consumer drains them. Turn on queued sending in **Settings > Configuration > Email Settings** (set the send method to *queue* / spool), then run the consumer on cron from the `workspace` container: ```cron * * * * * php bin/console messenger:consume email --time-limit=60 ``` Always pass at least one of `--time-limit`, `--memory-limit` or `--limit` so the consumer exits cleanly instead of running forever. For heavier sending, keep a long-lived worker running instead of a per-minute cron (see [Add a background worker](#add-a-background-worker-optional) below). ## Move the email queue to RabbitMQ (optional) The database transport is fine for modest volumes. For high-throughput sending you can point the Messenger queue at RabbitMQ instead. Start the container: ```bash ./laradock start rabbitmq ``` ```bash docker compose up -d rabbitmq ``` Then set the queue protocol in Mautic's `config/local.php`, using the service name as the host: ```php 'queue_protocol' => 'rabbitmq', 'rabbitmq_host' => 'rabbitmq', 'rabbitmq_port' => 5672, 'rabbitmq_vhost' => '/', 'rabbitmq_user' => 'guest', 'rabbitmq_password' => 'guest', ``` Run the same `messenger:consume email` command as before; it now pulls from RabbitMQ. The RabbitMQ credentials and vhost live in Laradock's `.env` (`RABBITMQ_DEFAULT_USER`, `RABBITMQ_DEFAULT_PASS`, `RABBITMQ_DEFAULT_VHOST`); match them here. Without this wiring the RabbitMQ container just sits idle, which is why the required stack leaves it out. ## Add a background worker (optional) Running `messenger:consume` from cron every minute is simple but bursty. For steady, high-volume sends, run a long-lived consumer instead. Laradock ships a `php-worker` container built exactly for this. Point its Supervisor config at the Mautic console command, for example: ```ini [program:mautic-email] command=php /var/www/my-mautic-instance/bin/console messenger:consume email --time-limit=3600 --memory-limit=256M autorestart=true numprocs=1 ``` Then start it: ```bash ./laradock start php-worker ``` ```bash docker compose up -d php-worker ``` Supervisor restarts the consumer whenever the time or memory limit trips it, so email keeps draining without a per-minute cron. This is the same pattern you would use in production. ## Catch outgoing email locally (optional) You do not want test campaigns hitting real inboxes. Start a mail catcher and point Mautic at it, and every message lands in a local web UI instead of the internet. Laradock includes several; `mailpit` is a good default: ```bash ./laradock start mailpit ``` ```bash docker compose up -d mailpit ``` Then set the mailer in **Settings > Configuration > Email Settings**, or directly in `config/local.php`, using the service name as the host: ```php 'mailer_dsn' => 'smtp://mailpit:1025', ``` Open the catcher's web UI (Mailpit defaults to [http://localhost:8025](http://localhost:8025)) to read anything Mautic sends. Swap in your real SMTP or API transport when you go live. ## Build and refresh Mautic assets Mautic ships compiled CSS and JS, and from Mautic 5 building them from source requires Node, which the `workspace` container already has. After changing themes, installing a plugin, or pulling a new release, regenerate the combined asset files from inside the workspace: ```bash php bin/console mautic:assets:generate php bin/console cache:clear ``` If a plugin ships its own front-end sources, run `npm install && npm run build` in that plugin's directory first; you never install Node on your host. ## Import an existing Mautic database Moving an existing instance onto Laradock is a straight MySQL restore. Copy your dump into the `workspace` container (or place it in the mounted project folder), then load it into the `mysql` service: ```bash mysql -h mysql -u default -psecret default < mautic-backup.sql ``` Copy the old `config/local.php` alongside your codebase but fix the connection lines to point at the containers (`db_host` = `mysql`), run `composer install`, then `php bin/console cache:clear`. Your contacts, campaigns and segments come across intact. To bulk-load contacts from a CSV instead of a full database, use `php bin/console mautic:import`. ## First admin login and CLI tooling The `--admin_email` and `--admin_password` you passed to `mautic:install` are your first login at [http://localhost](http://localhost); change the password from the profile menu once you are in. Everything else is driven from the console inside `workspace`: ```bash php bin/console cache:clear # after config or plugin changes php bin/console mautic:update:find # check for a new Mautic release php bin/console mautic:update:apply # apply it, then run migrations php bin/console doctrine:migrations:migrate php bin/console mautic:reports:scheduler # send scheduled reports ``` Because the console lives in the container, you never need PHP or Composer on your host to run any of it. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` Current Mautic releases target PHP 8.1 or newer; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older Mautic instance you have not upgraded yet and a brand-new one side by side, each isolated, none of it installed on your machine. ## Take your Mautic instance live When your instance is ready, the same Laradock stack becomes your deployment. You build one hardened image of your app and ship it to the host of your choice: ```bash ./laradock ship ``` Then pick a target and follow its short guide, a single server, a managed platform, or Kubernetes: **[Deploy to Production](https://laradock.io/docs/production)** lists every provider (Fly.io, Render, Railway, DigitalOcean, AWS, Google Cloud, Azure, Kamal, Kubernetes) with a ready config file for each. There is no per-provider magic to learn; a Docker image runs the same everywhere. Remember to carry the cron entries and a running email consumer into production too, since Mautic does nothing on a schedule without them. ## Frequently Asked Questions ### Do I need to install PHP or Composer to run Mautic with Laradock? No. Everything lives inside the containers. Composer, Node, git and the Symfony console are all in the `workspace` container; you never install PHP on your host. ### Which services should I start for a typical Mautic instance? `nginx mysql workspace` covers it: web server, database, and a shell to run the installer, updates, cron and the email consumer from. Swap `mysql` for `mariadb` if you prefer. The email queue uses the database by default, so no extra service is required until you choose to [add RabbitMQ](#move-the-email-queue-to-rabbitmq-optional) or a [mail catcher](#catch-outgoing-email-locally-optional). ### Does Mautic need cron to actually run campaigns? Yes, and that is true regardless of how it is hosted. Segment updates, campaign triggers and message sends all run through console commands, so schedule them (via cron in the `workspace` container or Laradock's `cron` service) as shown in [Keep Mautic running](#keep-mautic-running-cron-and-the-scheduler). Nothing fires just because someone visits the site. ### How does email sending work in Mautic 5 on Docker? Mautic 5 queues email through Symfony Messenger and drains it with `messenger:consume email`, run either on a per-minute cron or as a long-lived [background worker](#add-a-background-worker-optional). The default queue is the database, so it works on the base `nginx mysql workspace` stack with no extra service. ### Can I run multiple Mautic instances on different PHP versions? Yes. Give each its own Laradock with a unique `COMPOSE_PROJECT_NAME` and `DATA_PATH_HOST`, set a different `PHP_VERSION` in each, and they run independently on the same machine. ### Is this the same Docker setup I would use in production? The containers are production-style (real NGINX + PHP-FPM), so it is far closer to production than a native install. Mautic is heavier than a typical CRUD app, budget real memory and CPU for campaign processing, and carry the cron entries and email consumer over. See [Prepare Laradock for Production](https://laradock.io/docs/production#prepare-laradock-for-production) for the hardening steps. --- Comparing environments? See the full **[Laradock vs Others](https://laradock.io/docs/laradock-alternatives)** breakdown. Ready to start? **[Getting Started](https://laradock.io/docs/getting-started)** takes about five minutes. ================================================================ # Run MediaWiki on Docker Source: https://laradock.io/docs/mediawiki-on-docker ================================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What is MediaWiki? [MediaWiki](https://www.mediawiki.org) is the open-source wiki software that powers Wikipedia and thousands of other wikis, known for its extension and skin ecosystem and its ability to handle very large, heavily-edited content collections. It is a PHP application backed by a database (MySQL/MariaDB is recommended; PostgreSQL and SQLite are also supported), served through a web server. To boot and edit a wiki it needs only those two pieces. Everything else, full-text search, object caching, a background job runner, and outgoing email, is optional and added when a wiki gets real traffic. ## Why run MediaWiki in Docker? Docker packages each of those pieces (Apache, PHP-FPM, MySQL) into isolated containers that run the same on every machine. Instead of installing PHP and MySQL onto your laptop, where versions collide between sites and "works on my machine" starts, you run disposable containers that mirror production and vanish cleanly when you delete them. One wiki can run the newer PHP MediaWiki now requires while another project stays on an older version, on the same computer, with nothing installed globally. The catch: wiring those containers together yourself (base images, PHP extensions, networking, permissions) is a week of fiddly Docker work. That is exactly what Laradock removes. ## Why Laradock is the best fit for MediaWiki Docker Hub does host a `mediawiki` image, but it is a generic Docker Official Image maintained by Docker, not a production tool endorsed by the MediaWiki project; it intentionally ships the bare minimum and is meant to be extended from, not run as-is. There is no first-party MediaWiki tool that wires up a web server, database, search and caching the way a project-specific setup would. Here is why Laradock is the best fit instead: - **You are never locked into one ecosystem.** Laradock is framework-agnostic. Run your MediaWiki instance today, add a Laravel API, a WordPress site, or a plain PHP script beside it tomorrow, all in the same environment with the same commands. - **Far more flexibility.** 100+ ready services and any PHP version from 5.6 to 8.5, so an older wiki install and a fresh one each get exactly the runtime they need. - **Nothing is hidden and you own everything.** No generated files, no magic, no wrapper binary between you and Docker. Every Dockerfile and compose file is right there for you to read and edit. - **Nothing new to learn.** What you use is plain `docker compose`, knowledge that transfers straight to production. Our [CLI](https://laradock.io/docs/cli) is an optional nicety, never a requirement. Concretely, for MediaWiki it gives you a production-style Apache + PHP-FPM stack, MySQL/MariaDB/PostgreSQL ready to connect, a `workspace` container with git, Composer and PHP's CLI (for the installer, maintenance scripts and the job queue), and Elasticsearch, Redis and a mail catcher each one command away when you want them. ## Run MediaWiki on Docker with Laradock ### 1. Add Laradock to your project ```bash cd my-wiki git clone https://github.com/laradock/laradock.git cd laradock ``` (No MediaWiki files yet? Clone Laradock first, then download the MediaWiki tarball from the `workspace` container in the next steps.) ### 2. Pick the services your wiki needs MediaWiki needs exactly two things: a **web server** and a **database**. The web server pulls in PHP-FPM automatically, so this is the whole required stack: ```bash ./laradock start apache2 mysql workspace ``` ```bash cp .env.example .env docker compose up -d apache2 mysql workspace ``` Apache is the smoothest default for MediaWiki because its short-URL rewrites and the security `.htaccess` files in `images/` and `cache/` work with no extra config. Prefer NGINX? Swap the name (`./laradock start nginx mysql workspace`) and add MediaWiki's [NGINX rewrite rules](https://www.mediawiki.org/wiki/Manual:Short_URL/Nginx) by hand. Prefer PostgreSQL or MariaDB over MySQL? Swap that name too. The full catalog is [here](https://laradock.io/docs/Intro#supported-services). Prefer to be asked? The optional [CLI](https://laradock.io/docs/cli) walks you through the choices: `./laradock setup`, then `./laradock start`. It prints every real command it runs. > **Do I need Redis or a search server?** Not to get running. A fresh wiki runs perfectly on `apache2 mysql workspace`. Search falls back to a built-in database search, and caching falls back to the database. You add [Redis](#add-redis-object-caching-optional) and [CirrusSearch](#add-full-text-search-with-cirrussearch-optional) only when a busy wiki needs them, each covered below. ### 3. Point MediaWiki at the containers In your `LocalSettings.php`, use the service names as hostnames: ```php $wgDBtype = 'mysql'; $wgDBserver = 'mysql'; $wgDBname = 'default'; $wgDBuser = 'default'; $wgDBpassword = 'secret'; ``` The default database, user and password live in `mysql/defaults.env`; override any of them by adding the line to Laradock's `.env` (it always wins). ### 4. Install and run your wiki Enter the `workspace` container, where git, Composer and PHP's CLI live: ```bash ./laradock workspace ``` ```bash docker compose exec workspace bash ``` If you have no MediaWiki files yet, download and unpack a release tarball into your project (the tarball already includes its `vendor/` dependencies): ```bash curl -LO https://releases.wikimedia.org/mediawiki/1.43/mediawiki-1.43.1.tar.gz tar -xzf mediawiki-1.43.1.tar.gz --strip-components=1 ``` Then finish setup in the browser at [http://localhost](http://localhost), or run the CLI installer (the maintenance script that writes `LocalSettings.php` and creates your first admin for you): ```bash php maintenance/install.php --dbserver=mysql --dbname=default \ --dbuser=default --dbpass=secret --pass=adminpassword \ "My Wiki" Admin ``` That command creates a sysop account named `Admin` with the password you pass in `--pass`. On MediaWiki 1.40 and newer the same script is also reachable as `php maintenance/run.php install`, and the exact flags can vary by release, so run it with `--help` to confirm. Then open [http://localhost](http://localhost) and log in at **Special:UserLogin** with `Admin` and your password. That is a full MediaWiki install running on Docker. ## Add Redis object caching (optional) Out of the box MediaWiki caches to the database, which is fine for a small wiki. On a busier one, Redis holds the object and session cache in memory and takes noticeable load off MySQL. Wiring it up is two steps: 1. Start the Redis container alongside the rest: ```bash ./laradock start redis ``` ```bash docker compose up -d redis ``` 2. Point MediaWiki at it in `LocalSettings.php`: ```php $wgObjectCaches['redis'] = [ 'class' => 'RedisBagOStuff', 'servers' => [ 'redis:6379' ], ]; $wgMainCacheType = 'redis'; $wgSessionCacheType = 'redis'; ``` That is it, MediaWiki now stores its object and session cache in Redis. Prefer Memcached? Start `memcached` instead, then set `$wgMainCacheType = CACHE_MEMCACHED;` and `$wgMemCachedServers = [ 'memcached:11211' ];`. Without either step the container just sits idle, which is why the required stack above leaves it out. ## Add full-text search with CirrusSearch (optional) MediaWiki's default search reads straight from the database and is fine for a small wiki. For fast, relevant full-text search (what Wikipedia uses) you add the **CirrusSearch** extension backed by Elasticsearch or OpenSearch. 1. Start the search container: ```bash ./laradock start elasticsearch ``` ```bash docker compose up -d elasticsearch ``` (MediaWiki 1.44+ can also run against `opensearch`; start that container instead if you prefer it.) 2. From the `workspace` container, add the `Elastica` and `CirrusSearch` extensions into your `extensions/` folder (both ship with the tarball, or clone the matching `REL` branch), then enable them in `LocalSettings.php` and point CirrusSearch at the container: ```php wfLoadExtension( 'Elastica' ); wfLoadExtension( 'CirrusSearch' ); $wgCirrusSearchClusters = [ 'default' => [ 'elasticsearch:9200' ] ]; $wgSearchType = 'CirrusSearch'; ``` 3. Still in the `workspace`, build the index and backfill your existing pages: ```bash php extensions/CirrusSearch/maintenance/UpdateSearchIndexConfig.php php extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipLinks --indexOnSkip php extensions/CirrusSearch/maintenance/ForceSearchIndex.php --skipParse ``` New edits stay indexed automatically through the [job queue](#run-the-job-queue-in-the-background), so turn that on next. ## Catch outgoing email in development (optional) Password resets, watchlist notifications and account confirmations all send mail. In development you do not want real email leaving your machine, so route it to **Mailpit**, which catches every message in a web inbox. 1. Start the catcher: ```bash ./laradock start mailpit ``` ```bash docker compose up -d mailpit ``` 2. Point MediaWiki's SMTP at it in `LocalSettings.php`: ```php $wgEnableEmail = true; $wgSMTP = [ 'host' => 'mailpit', 'IDHost' => 'localhost', 'port' => 1025, 'auth' => false, ]; $wgEmergencyContact = 'admin@localhost'; $wgPasswordSender = 'admin@localhost'; ``` Every message MediaWiki sends now lands in the Mailpit inbox at [http://localhost:8025](http://localhost:8025) instead of a real mailbox. Swap `mailpit` for `mailhog` (port 1025, inbox on 8025) if you prefer that catcher. ## Run the job queue in the background MediaWiki defers slow work, link updates, search re-indexing, HTML cache purges, email, onto a **job queue**. By default it runs a few of those jobs on each web request, which makes some page loads slower. On any real wiki you turn that off and run a dedicated worker instead. In `LocalSettings.php`, stop jobs from piggybacking on requests: ```php $wgJobRunRate = 0; ``` Then, from the `workspace` container, drain the queue continuously: ```bash php maintenance/run.php runJobs --wait ``` `--wait` keeps the process alive and picks up new jobs as they appear, so leave that shell open (or run it as a background worker) while you develop. On older MediaWiki the script is `php maintenance/runJobs.php`. For a Redis-backed queue that survives restarts, add `$wgJobTypeConf['default'] = [ 'class' => 'JobQueueRedis', 'redisServer' => 'redis:6379', 'redisConfig' => [] ];` after starting the `redis` container. ## Schedule maintenance with cron A production wiki runs a handful of maintenance scripts on a schedule: draining the job queue, refreshing stale links, and expiring old data. From inside the `workspace` container you can add them to cron so they run unattended: ```cron # drain the job queue every minute * * * * * cd /var/www/my-wiki && php maintenance/run.php runJobs --maxtime=50 >> /dev/null 2>&1 # rebuild link tables nightly 0 2 * * * cd /var/www/my-wiki && php maintenance/run.php refreshLinks >> /dev/null 2>&1 ``` Any maintenance script can be scheduled the same way. If you would rather not keep a shell open, this replaces the long-running `runJobs --wait` worker from the previous section. ## Change the PHP version anytime This is where a native install hurts and Laradock shines. Set the version in Laradock's `.env` and rebuild: ```env PHP_VERSION=8.3 ``` ```bash ./laradock rebuild php-fpm workspace ``` ```bash docker compose build php-fpm workspace ``` MediaWiki's current stable release requires PHP 8.1 or newer, with the newest release requiring PHP 8.3+; Laradock covers anything from PHP 5.6 to 8.5, so the same tool runs an older wiki pinned to an older PHP version and a brand-new install side by side, each isolated, none of it installed on your machine. ## Install extensions and skins MediaWiki's front-end assets are served at runtime by its built-in ResourceLoader, so there is no separate build step to run for the core software: install an extension or skin and it just works. From the `workspace` container: 1. Drop the extension into `extensions/` (or a skin into `skins/`), either from the tarball's bundle or by cloning the matching release branch: ```bash git clone -b REL1_43 https://github.com/wikimedia/mediawiki-extensions-VisualEditor.git extensions/VisualEditor ``` 2. If the extension ships a `composer.json`, install its PHP dependencies from inside that folder: ```bash composer update --no-dev --working-dir=extensions/VisualEditor ``` 3. Enable it in `LocalSettings.php` and apply any database changes it needs: ```php wfLoadExtension( 'VisualEditor' ); ``` ```bash php maintenance/run.php update --quick ``` `update.php` is the script you run after adding any extension, updating one, or upgrading MediaWiki itself; it applies schema changes safely and is idempotent. ## Run maintenance scripts from the workspace Everything MediaWiki does from the command line lives in `maintenance/` and runs from the `workspace` container with `php maintenance/run.php