├── .github
└── workflows
│ └── run-tests.yml
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── logo.jpg
├── logo.png
├── phpunit.xml.dist
├── src
├── Commands
│ ├── ServedListCommand.php
│ ├── ServedRunCommand.php
│ ├── ServedSshCommand.php
│ ├── ServedStartCommand.php
│ ├── ServedStopCommand.php
│ ├── ServedTearDownCommand.php
│ ├── ServedUpCommand.php
│ ├── ServedXdebugCommand.php
│ └── Traits
│ │ ├── BindOutputToApp.php
│ │ ├── DockerCheck.php
│ │ ├── Logo.php
│ │ ├── PortCheck.php
│ │ └── RunningConfig.php
├── Containers
│ ├── ApacheContainer.php
│ ├── Container.php
│ ├── MailhogContainer.php
│ ├── MemcachedContainer.php
│ ├── MysqlContainer.php
│ ├── NginxContainer.php
│ ├── PhpContainer.php
│ ├── PostgresContainer.php
│ └── RedisContainer.php
├── Docker
│ ├── Docker.php
│ └── DockerFileBuilder.php
├── Exceptions
│ ├── DockerNotInstalledException.php
│ ├── DockerNotRunningException.php
│ ├── InvalidNamingException.php
│ ├── PortAlreadyInUseException.php
│ ├── ShellCommandFailedException.php
│ └── TtyNotSupportedException.php
├── Images
│ ├── ApacheImage.php
│ ├── Image.php
│ ├── ImageInterface.php
│ ├── MailhogImage.php
│ ├── MemcachedImage.php
│ ├── MysqlImage.php
│ ├── NginxImage.php
│ ├── PhpImage.php
│ ├── PostgresImage.php
│ ├── RedisImage.php
│ └── stubs
│ │ ├── localhost.crt
│ │ ├── localhost.key
│ │ ├── my-httpd-vhosts.conf
│ │ ├── my-httpd.conf
│ │ └── nginx.conf
├── ServedName.php
├── ServedServiceProvider.php
├── ServiceManager.php
├── Services
│ ├── ApacheService.php
│ ├── MailhogService.php
│ ├── MemcachedService.php
│ ├── MysqlService.php
│ ├── NginxService.php
│ ├── PhpService.php
│ ├── PostgresService.php
│ ├── RedisService.php
│ ├── Service.php
│ └── ServiceInterface.php
├── Shell
│ ├── Process.php
│ └── Shell.php
├── Traits
│ └── Storage.php
└── config
│ └── served.php
└── tests
├── TestCase.php
├── Unit
├── DockerImageTest.php
├── DockerRunTest.php
└── NamingTest.php
└── expected
├── DockerFile-apache
├── DockerFile-mailhog
├── DockerFile-memcached
├── DockerFile-mysql
├── DockerFile-nginx
├── DockerFile-php
├── DockerFile-postgres
└── DockerFile-redis
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v2
12 |
13 | - name: Validate composer.json and composer.lock
14 | run: composer validate
15 |
16 | - name: Cache Composer packages
17 | id: composer-cache
18 | uses: actions/cache@v2
19 | with:
20 | path: vendor
21 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
22 | restore-keys: |
23 | ${{ runner.os }}-php-
24 |
25 | - name: Install dependencies
26 | if: steps.composer-cache.outputs.cache-hit != 'true'
27 | run: composer install --prefer-dist --no-progress --no-suggest
28 |
29 | - name: Run tests
30 | run: composer test
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /.idea
3 | .phpunit.result.cache
4 | .php_cs.cache
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 René Sinnbeck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://packagist.org/packages/sinnbeck/laravel-served)
4 | [](https://packagist.org/packages/sinnbeck/laravel-served)
5 | 
6 |
7 | # Introduction
8 |
9 | Laravel Served is a dockerized version of `php artisan serve`. It makes it easy to quickly start a development environment the laravel way (through a config file).
10 |
11 | The only things you need to get started is
12 | * Php (cli)
13 | * Docker
14 | * Laravel
15 |
16 | >Beware: This package is under active development and major changes can occur at any point. It is therefore a good idea to read the documentation, and republish the config file after each new version.
17 |
18 | ## Available services
19 | These are the available services that Served provide. More will be added in the future. If you are missing something specific, just create a new issue, requesting it.
20 | * Php
21 | * Nginx
22 | * Apache2
23 | * Mysql
24 | * Postgres
25 | * Redis
26 | * Memcached
27 | * Mailhog
28 |
29 | ## Installation
30 | Install the package using composer
31 | ```
32 | $ composer require sinnbeck/laravel-served --dev
33 | ```
34 |
35 | ## Running for the first time
36 | It is possible to just start a development server right away after installation. This will bring up 3 docker images:
37 |
38 | |Image|Version|Misc|
39 | |-----|-------|------|
40 | |Php-fpm|7.4|Preinstalled with composer, required php modules for running laravel and xdebug running on port 9000 with IDE key 'served'|
41 | |Nginx|1.19|N/A|
42 | |Mysql|5.7|
- Hostname: mysql
- Database: laravel
- Username: laravel
- Password: password
|
43 |
44 | To start the containers simply run
45 | ```
46 | $ php artisan served:up
47 | ```
48 | If this is your first time running the command, it will build the images first before starting the containers. If you have run the `served:up` command before, docker will quickly check the images for updates and served will start the containers again.
49 |
50 | ## Starting and stopping served
51 | After your first run, you can easily start and stop your containers without having to build either images or containers. Simply run
52 | ```
53 | $ php artisan served:start
54 | ```
55 | And to stop the containers again without removing anything.
56 | ```
57 | $ php artisan served:stop
58 | ```
59 | This is useful to free up ports if you have several projects using the same.
60 |
61 | ## Ssh
62 | To go into a container to work you can run
63 | ```
64 | $ php artisan served:ssh container_name
65 | ```
66 | The `container_name` is optional, and will default to php (where you can run artisan etc.).
67 |
68 | >Served doesn't actually ssh into the container, but rather just start a bash shell directly. `served:ssh`just sound better and is quick to type.
69 |
70 | ## Clean up
71 | It is possible to remove all data set up by served. To do this simply run
72 | ```
73 | $ php artisan served:teardown
74 | ```
75 |
76 | ## Configuration
77 | While it is possible to just run served without any configuration, it is probably a good idea to configure served for your needs.
78 | To get started you need to publish the config file.
79 | ```
80 | $ php artisan vendor:publish --provider="Sinnbeck\LaravelServed\ServedServiceProvider"
81 | ```
82 | ### Name
83 | To avoid naming conflicts between projects, you can define your own name for served configuration. This name will be used when creating network, images and containers. Make sure it is unique between projects! If no name is set, served will use the folder name of the laravel installation (a slug version)
84 |
85 | It is important the name only consists of letters, numbers, `.`, `-` and `_`. Other special characters will throw an exception.
86 |
87 | If you at some point wish to chance the name after having used served on a project, it is important to teardown both images and containers using `served:teardown`. If you have already changed the name and are having issues getting your containers up and running with the new name, just chance the name back, run teardown, and set it to the new name once more.
88 |
89 | ### Php
90 | Here you may specify how php should be built. Any options left blank or removed will be defaulted to using the defaults provided by served.
91 |
92 | ```
93 | 'php' => [
94 | 'version' => env('SERVED_PHP_VERSION', '7.4'),
95 | 'modules' => [
96 | 'pdo_mysql',
97 | 'zip',
98 | ],
99 | 'npm' => true, //enable or disable npm in build
100 | 'xdebug' => [
101 | 'enabled' => env('SERVED_XDEBUG_ENABLED', true),
102 | 'port' => 9001,
103 | ],
104 | ],
105 | ```
106 |
107 | The array of modules can be filled with any module found in the url below (except parallel, pthreads and tdlib)
108 |
109 | https://github.com/mlocati/docker-php-extension-installer
110 |
111 | #### Xdebug
112 | It is suggested to install xdebug to make debugging easier. To install it and set it up, simple make sure it is set as enabled in the config, while running `php artisan served:up php`
113 |
114 | As Xdebug can slow down requests, it is possible to quickly turn it off and on, when needed.
115 |
116 | Enable Xdebug
117 | ```
118 | $ php artisan served:xdebug enable
119 | ```
120 | Disable Xdebug
121 | ```
122 | $ php artisan served:xdebug disable
123 | ```
124 | Interactive toggle Xdebug
125 | ```
126 | $ php artisan served:xdebug
127 | ```
128 | Be aware that you need to run `php artisan served:up php` again if you decide to enable Xdebug in the config. It isn't possible to toggle it on an off if it isn't installed in the first place.
129 |
130 | ### Web
131 | Served currently supports nginx and apache. Simply service to whichever you want to use, and set the correct version (or delete the version to have served use a sensible default). Apache currently only supports the latest version and will ignore any version set.
132 |
133 | ```
134 | 'web' => [
135 | 'service' => 'nginx', //or apache
136 | 'version' => '1.9.2',
137 | 'port' => env('SERVED_WEB_PORT', 8095),
138 | 'ssl_port' => env('SERVED_WEB_SSL_PORT', 4443),
139 | ],
140 | ```
141 | If you are trying to use the https address, you will be shown a certificate error. To fix this in Chrome, open chrome://settings/certificates and select the Authorities tab. Click import and find the `localhost.crt` in your `/storage/app/served/web/` directory
142 |
143 | ## Extras
144 | Here you can define extra images that you wish to run. The array key is used as name, meaning it is possible to run the same service more than once, with different names (eg. two mysql instances).
145 |
146 | The current supported images are:
147 |
148 | ### Mysql
149 | Port is used for when connecting to mysql from outside of laravel.
150 | Eg. 127.0.0.1:3306.
151 |
152 | To connect to the database from laravel you need to use the config key (in the example that would be `mysql`) as hostname. The port is the default for mysql (3306) and not the one specified in the config.
153 |
154 | If you wish to override the port you use connect to mysql from outside your docker, you can do so by adding 'SERVED_EXTERNAL_DB_PORT' to your .env
155 | ```
156 | 'mysql' => [
157 | 'service' => 'mysql',
158 | 'version' => '5.7',
159 | 'port' => env('SERVED_EXTERNAL_DB_PORT', 3306),
160 | 'root_password' => 'password',
161 | 'database' => env('DB_DATABASE', 'laravel'),
162 | 'username' => env('DB_USERNAME', 'laravel'),
163 | 'password' => env('DB_PASSWORD', 'password'),
164 | ],
165 | ```
166 |
167 | ### Postgres
168 | To connect to postgresql from laravel you need to use the config key (in the example that would be `postgres`) as hostname. The port is the default for mysql (5432) and not the one specified in the config. To connect from outside of laravel, use the port specified in the config (eg. 54320) and 127.0.0.1
169 | ```
170 | 'postgres' => [
171 | 'service' => 'postgres',
172 | 'version' => '12.4',
173 | 'port' => 54320,
174 | 'database' => 'laravel',
175 | 'username' => 'laravel',
176 | 'password' => 'password',
177 | ],
178 | ```
179 |
180 | ### Redis
181 | Add redis to the modules in php and then add redis to your extras array.
182 | ```
183 | 'redis' => [
184 | 'service' => 'redis',
185 | ]
186 | ```
187 | Change your `REDIS_HOST` in .env to whatever you use as the key (eg. redis)
188 |
189 | ### Memcached
190 | Add memcached to the modules in php and then add memcached to your extras array.
191 | ```
192 | 'memcached' => [
193 | 'service' => 'memcached',
194 | ]
195 | ```
196 | Change your `CACHE_DRIVER` in .env to `memcached` and add `MEMCACHED_HOST` and set it to whatever you use as the key (eg. memcached)
197 |
198 | ### Mailhog
199 | Add mailhog to your extras array.
200 | ```
201 | 'mail' => [
202 | 'service' => 'mailhog',
203 | 'port' => 8025
204 | ]
205 | ```
206 | Change your `MAIL_HOST` in .env to whatever you use as the key (eg. mail), and change `MAIL_PORT`to 1025. To see the mailbox, open http://localhost:8025 in your browser (replace 8025 with whatever port you set in config)
207 |
208 | ## Testing
209 | Run tests with
210 | ```
211 | $ composer test
212 | ```
213 |
214 |
215 | ## Todo
216 | - [ ] Testing!
217 | - [ ] Add more images
218 | - [ ] Allow user created services
219 | - [ ] Let served make a proper name if none is set (instead of defaulting to 'served')
220 | - [ ] Handle setting/adding volumes
221 | - [ ] Handle removal of volumes
222 | - [ ] Handle upgrades/downgrades of images
223 | - [ ] Pass cli output interface to other classes to allow outputting to cli from them
224 | - [x] Test on other platforms than linux (Ubuntu)
225 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sinnbeck/laravel-served",
3 | "description": "Dockerized version of artisan serve",
4 | "keywords": [
5 | "laravel",
6 | "serve",
7 | "docker",
8 | "webserver",
9 | "apache",
10 | "nginx"
11 | ],
12 | "license": "MIT",
13 | "authors": [
14 | {
15 | "name": "René Sinnbeck",
16 | "email": "rene.sinnbeck@gmail.com"
17 | }
18 | ],
19 | "require": {},
20 | "require-dev": {
21 | "symfony/process": "^5.1",
22 | "laravel/framework": ">=6.0",
23 | "orchestra/testbench": "^4.0 || ^5.0 || ^6.0",
24 | "phpunit/phpunit": "^8.0 || ^9.0"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Sinnbeck\\LaravelServed\\": "src/"
29 | }
30 | },
31 | "autoload-dev": {
32 | "psr-4": {
33 | "Tests\\": "tests/"
34 | }
35 | },
36 | "extra": {
37 | "branch-alias": {
38 | "dev-master": "0.1-dev"
39 | },
40 | "laravel": {
41 | "providers": [
42 | "Sinnbeck\\LaravelServed\\ServedServiceProvider"
43 | ]
44 | }
45 | },
46 | "minimum-stability": "stable",
47 | "scripts": {
48 | "test": "vendor/bin/phpunit"
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sinnbeck/laravel-served/85deb6d824384dd6f442e0e4a5cb5d350d1cc64b/logo.jpg
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sinnbeck/laravel-served/85deb6d824384dd6f442e0e4a5cb5d350d1cc64b/logo.png
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 | src/
17 |
18 |
19 |
20 |
21 | tests
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Commands/ServedListCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
51 | $containers = $docker->listContainers();
52 |
53 | $this->drawLogo();
54 | $this->comment(app('served.name'));
55 | $this->table($containers->slice(0, 1)->toArray(), $containers->slice(1)->toArray());
56 |
57 | return 0;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Commands/ServedRunCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
58 | try {
59 | $this->checkPortConflicts($docker, $manager);
60 |
61 | }
62 | catch (PortAlreadyInUseException $e) {
63 | $this->error($e->getMessage());
64 | return 1;
65 | }
66 |
67 | $servedName = app('served.name');
68 | $docker->ensureNetworkExists($servedName);
69 |
70 | $onlyService = $this->argument('service');
71 |
72 | $serviceList = $manager->loadServices();
73 |
74 | try {
75 | foreach ($serviceList as $service) {
76 | if ($onlyService && $service->name() !== $onlyService) {
77 | continue;
78 | }
79 | $this->info(sprintf('Starting %s (%s) ...', $service->name(), $service->imageName()));
80 | $service->container()->remove();
81 | $service->container()->run();
82 |
83 | }
84 |
85 | } catch (ShellCommandFailedException $exception) {
86 | $this->error($exception->getMessage());
87 | return 1;
88 | }
89 | $this->line('');
90 | $this->servedRunning($manager);
91 | return 0;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Commands/ServedSshCommand.php:
--------------------------------------------------------------------------------
1 | argument('service');
49 | $service = $manager->resolveByName($serviceName);
50 |
51 | try {
52 | $service->container()->ssh();
53 |
54 | } catch (TtyNotSupportedException $e) {
55 | $this->error('Your platform does not support TTY. This means that artisan cannot handle the docker shell.');
56 | $this->line(sprintf('Instead run %s> manually', $service->container()->fallbackSsh()));
57 | }
58 |
59 | return 0;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Commands/ServedStartCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
57 | try {
58 | $this->checkPortConflicts($docker, $manager);
59 |
60 | }
61 | catch (PortAlreadyInUseException $e) {
62 | $this->error($e->getMessage());
63 | return 1;
64 | }
65 |
66 | $this->comment('Ensuring old containers are stopped ...');
67 | $this->callSilent('served:stop');
68 |
69 | $servedName = app('served.name');
70 | $docker->ensureNetworkExists($servedName);
71 |
72 | $onlyService = $this->argument('service');
73 |
74 | $serviceList = $manager->loadServices();
75 |
76 | foreach ($serviceList as $service) {
77 | if ($onlyService && $service->name() !== $onlyService) {
78 | continue;
79 | }
80 | $this->info(sprintf('Starting %s (%s) ...', $service->name(), $service->imageName()));
81 | $service->container()->start();
82 |
83 | }
84 | $this->line('');
85 | $this->servedRunning($manager);
86 | return 0;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Commands/ServedStopCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
52 | $servedName = app('served.name');
53 | $docker->ensureNetworkExists($servedName);
54 |
55 | $onlyService = $this->argument('service');
56 |
57 | $serviceList = $manager->loadServices();
58 |
59 | foreach ($serviceList as $service) {
60 | if ($onlyService && $service->name() !== $onlyService) {
61 | continue;
62 | }
63 | $this->info(sprintf('Stopping %s (%s) ...', $service->name(), $service->imageName()));
64 | $service->container()->stop();
65 |
66 | }
67 |
68 | return 0;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Commands/ServedTearDownCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
53 | $servedName = app('served.name');
54 |
55 | $onlyService = $this->argument('service');
56 |
57 | $serviceList = $manager->loadServices();
58 |
59 | foreach ($serviceList as $service) {
60 | if ($onlyService && $service->name() !== $onlyService) {
61 | continue;
62 | }
63 |
64 | $this->info(sprintf('Removing container for %s (%s) ...', $service->name(), $service->imageName()));
65 |
66 | $service->container()->remove();
67 |
68 | }
69 |
70 | foreach ($serviceList as $service) {
71 | if ($onlyService && $service->name() !== $onlyService) {
72 | continue;
73 | }
74 |
75 | $this->info(sprintf('Removing image for %s (%s) ...', $service->name(), $service->imageName()));
76 |
77 | $service->image()->remove();
78 |
79 | }
80 |
81 | if (!$onlyService) {
82 | $this->info(sprintf('Removing network %s ...', $servedName));
83 | $docker->removeNetwork($servedName);
84 | }
85 |
86 | return 0;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Commands/ServedUpCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
58 | try {
59 | $this->checkPortConflicts($docker, $manager);
60 |
61 | }
62 | catch (PortAlreadyInUseException $e) {
63 | $this->error($e->getMessage());
64 | return 1;
65 | }
66 |
67 | $servedName = app('served.name');
68 | $this->info('Creating network: ' . $servedName);
69 | $docker->ensureNetworkExists($servedName);
70 |
71 | $onlyService = $this->argument('service');
72 | $noCache = $this->option('no-cache');
73 | $serviceList = $manager->loadServices();
74 |
75 | try {
76 | foreach ($serviceList as $service) {
77 | if ($onlyService && $service->name() !== $onlyService) {
78 | continue;
79 | }
80 |
81 | $this->info(sprintf('Building %s (%s) ...', $service->name(), $service->imageName()));
82 | $service->build($noCache);
83 |
84 | }
85 |
86 | foreach ($serviceList as $service) {
87 | if ($onlyService && $service->name() !== $onlyService) {
88 | continue;
89 | }
90 | $this->info(sprintf('Starting %s (%s) ...', $service->name(), $service->imageName()));
91 | $service->run();
92 |
93 | }
94 |
95 | } catch (ShellCommandFailedException $exception) {
96 | $this->error($exception->getMessage());
97 | return 1;
98 | }
99 |
100 | $this->servedRunning($manager);
101 |
102 | return 0;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Commands/ServedXdebugCommand.php:
--------------------------------------------------------------------------------
1 | checkPrerequisites($docker);
52 |
53 | $service = $manager->resolveByName('php');
54 |
55 | if (!config( 'served.php.xdebug.enabled', false)) {
56 | $this->error('You aren\'t using xdebug!');
57 | return 1;
58 | }
59 |
60 | $argument = $this->argument('flag');
61 | if (!$argument) {
62 | $argument = $this->choice('Do you want to enable or disable?', ['enable', 'disable'], 0);
63 |
64 | }
65 |
66 | if ($argument == 'enable') {
67 | try {
68 | $service->enableXdebug();
69 | $this->info('Xdebug has been enabled!');
70 |
71 | }
72 | catch (ProcessFailedException $exception) {
73 | $this->error('Xdebug is already enabled!');
74 | }
75 |
76 | } elseif ($argument == 'disable') {
77 | try {
78 | $service->disableXdebug();
79 | $this->info('Xdebug has been disabled!');
80 |
81 | }
82 | catch (ProcessFailedException $exception) {
83 | $this->error('Xdebug is already disabled!');
84 | }
85 |
86 | } else {
87 | $this->warn('Only enable and disable are supported.');
88 | }
89 |
90 | return 0;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/Commands/Traits/BindOutputToApp.php:
--------------------------------------------------------------------------------
1 | bindOutput($output);
17 | }
18 |
19 | /**
20 | * bind output to dependency container
21 | * @param OutputInterface $output
22 | */
23 | private function bindOutput(OutputInterface $output)
24 | {
25 | app()->singleton(OutputInterface::class, function() use ($output) {
26 | return $output;
27 | });
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Commands/Traits/DockerCheck.php:
--------------------------------------------------------------------------------
1 | verifyDockerIsInstalled();
18 |
19 | } catch (DockerNotInstalledException $e) {
20 | $this->error('Docker is not installed!');
21 | }
22 |
23 | try {
24 | $docker->verifyDockerDemonIsRunning();
25 |
26 | } catch (DockerNotRunningException $e) {
27 | $this->error('Docker daemon isn\'t running!');
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Commands/Traits/Logo.php:
--------------------------------------------------------------------------------
1 | line(' __ ___ __ ___ __
13 | /__` |__ |__) \ / |__ | \
14 | .__/ |___ | \ \/ |___ |__/
15 | ', 'fg=blue');
16 | }
17 |
18 | /**
19 | * @return void
20 | */
21 | protected function oldLogo(): void
22 | {
23 | $this->line(' _____ _
24 | | __|___ ___ _ _ ___ _| |
25 | |__ | -_| _| | | -_| . |
26 | |_____|___|_| \_/|___|___|', 'fg=blue');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Commands/Traits/PortCheck.php:
--------------------------------------------------------------------------------
1 | loadServices();
15 |
16 | $servicesWithPort = collect($serviceList)->filter(function($service) {
17 | return !!$service->container()->port();
18 | });
19 |
20 | foreach ($servicesWithPort as $service) {
21 | $port = $service->container()->port();
22 | $internalPort = $service->container()->internalPort();
23 | $sslPort = $service->container()->sslPort();
24 | $internalSslPort = $service->container()->internalSslPort();
25 | if ($this->testPort($docker, $service, $port, $internalPort) && $this->testPort($docker, $service, $sslPort, $internalSslPort)) {
26 | continue;
27 | }
28 | }
29 | }
30 |
31 | protected function testPort(Docker $docker, Service $service, ?int $port = null, ?int $internalPort = null): bool
32 | {
33 | if (!$port) {
34 | return true;
35 | }
36 |
37 | if ($port == $docker->getUsedPort($service->name(), $internalPort)) {
38 | return true;
39 | }
40 |
41 | $connection = @fsockopen('localhost', $port);
42 |
43 | if (is_resource($connection))
44 | {
45 | fclose($connection);
46 | throw new PortAlreadyInUseException('Port ' . $port . ' is in use!');
47 | }
48 |
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Commands/Traits/RunningConfig.php:
--------------------------------------------------------------------------------
1 | line(' Laravel has been', 'fg=blue');
18 | $this->drawLogo();
19 | $url = 'http://localhost:' . $manager->web()->container()->port();
20 | $secureUrl = 'https://localhost:' . $manager->web()->container()->sslPort();
21 | $this->line('Visit the development server at:>');
22 | $this->line(''. $url . '>>');
23 | $this->line(''. $secureUrl . '>>');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Containers/ApacheContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
29 | 'container_name' => $this->makeContainerName(),
30 | 'image_name' => $this->makeImageName(),
31 | 'port' => $this->port(),
32 | 'ssl_port' => $this->sslPort(),
33 | 'local_dir' => base_path(),
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Containers/Container.php:
--------------------------------------------------------------------------------
1 | name = $name;
46 | $this->config = $config;
47 | $this->shell = $shell;
48 |
49 | $this->parseConfig();
50 | }
51 |
52 | /**
53 | * @return $this
54 | */
55 | public function prepare(): self
56 | {
57 | $this->remove();
58 |
59 | return $this;
60 | }
61 |
62 | public function run()
63 | {
64 | $this->shell->run($this->getDockerRunCommand(), $this->env());
65 | }
66 |
67 | public function getDockerRunCommand()
68 | {
69 |
70 | $command = $this->isWindows() ? str_replace('\\', '', $this->dockerRunCommand) : $this->dockerRunCommand;
71 |
72 | return 'docker run -d --restart always ' . $command . $this->getProxySettings() . ' "${:image_name}"';
73 | }
74 |
75 | protected function getProxySettings()
76 | {
77 | $envString = '';
78 | if ($proxyHttp = config('served.proxy.http', false)) {
79 | $envString .= ' --env=HTTP_PROXY="' . $proxyHttp . '"';
80 | }
81 |
82 | if ($proxyHttps = config('served.proxy.https', false)) {
83 | $envString .= ' --env=HTTPS_PROXY="' . $proxyHttps . '"';
84 | }
85 |
86 | return $envString;
87 | }
88 |
89 | public function getEnv()
90 | {
91 | return $this->env();
92 | }
93 |
94 | /**
95 | * @return void
96 | */
97 | public function parseConfig(): void
98 | {
99 | foreach ($this->config as $key => $value) {
100 | if ($key === 'port') {
101 | $this->setPort((int) $value);
102 | }
103 |
104 | if ($key === 'ssl_port') {
105 | $this->setSslPort((int) $value);
106 | }
107 | }
108 | }
109 |
110 | /**
111 | * @return void
112 | */
113 | public function start(): void
114 | {
115 | $this->shell->exec('docker start ' . $this->makeContainerName());
116 | }
117 |
118 | /**
119 | * @return void
120 | */
121 | public function stop(): void
122 | {
123 | $this->shell->exec('docker stop ' . $this->makeContainerName());
124 | }
125 |
126 | /**
127 | * @return array
128 | */
129 | protected function env()
130 | {
131 | $baseEnv = [
132 | 'network' => $this->projectName(),
133 | 'container_name' => $this->makeContainerName(),
134 | 'image_name' => $this->makeImageName(),
135 | ];
136 |
137 | return array_merge($baseEnv, $this->getAdditionalEnv());
138 | }
139 |
140 | /**
141 | * @return array
142 | */
143 | protected function getAdditionalEnv(): array
144 | {
145 | return [];
146 | }
147 |
148 | /**
149 | * @return void
150 | */
151 | public function remove(): void
152 | {
153 | try {
154 | $this->shell->exec('docker rm ' . $this->makeContainerName() . ' -f');
155 |
156 | } catch (ProcessFailedException $e) {
157 | //Do nothing
158 | }
159 | }
160 |
161 | /**
162 | * @throws TtyNotSupportedException
163 | */
164 | public function ssh(): void
165 | {
166 | if (!Process::isTtySupported()) {
167 | throw new TtyNotSupportedException('TTY mode is not supported');
168 | }
169 |
170 | $process = Process::fromShellCommandline('docker exec -ti "${:container}" bash');
171 |
172 | $process->setTimeout(null);
173 | $process->setTty(true);
174 |
175 | $process->run(null, ['container' => $this->makeContainerName()]);
176 | }
177 |
178 | /**
179 | * @return string
180 | */
181 | public function fallbackSsh(): string
182 | {
183 | return sprintf('docker exec -ti %s bash', $this->makeContainerName());
184 | }
185 |
186 | /**
187 | * @return string
188 | */
189 | protected function makeContainerName(): string
190 | {
191 | return sprintf('served_%s_%s', $this->projectName(), $this->name());
192 | }
193 |
194 | /**
195 | * @param int $port
196 | * @return $this
197 | */
198 | public function setPort(int $port): self
199 | {
200 | if ($port) {
201 | $this->port = (int) $port;
202 | }
203 |
204 | return $this;
205 | }
206 |
207 | /**
208 | * @return int
209 | */
210 | public function port(): ?int
211 | {
212 | return $this->port;
213 | }
214 |
215 | /**
216 | * @param int $port
217 | * @return $this
218 | */
219 | public function setSslPort(int $port): self
220 | {
221 | if ($port) {
222 | $this->ssl_port = (int) $port;
223 | }
224 |
225 | return $this;
226 | }
227 |
228 | /**
229 | * @return int
230 | */
231 | public function sslPort(): ?int
232 | {
233 | return $this->ssl_port;
234 | }
235 |
236 | /**
237 | * @return int
238 | */
239 | public function internalPort(): ?int
240 | {
241 | return $this->internal_port;
242 | }
243 |
244 | /**
245 | * @return int
246 | */
247 | public function internalSslPort(): ?int
248 | {
249 | return $this->internal_ssl_port;
250 | }
251 |
252 | /**
253 | * @return string
254 | */
255 | public function projectName(): string
256 | {
257 | return app('served.name');
258 | }
259 |
260 | /**
261 | * @return string
262 | */
263 | public function name(): string
264 | {
265 | return $this->name;
266 | }
267 |
268 | /**
269 | * @return string
270 | */
271 | protected function findDockerFile(): string
272 | {
273 | return $this->storageDirectory() . 'Dockerfile';
274 | }
275 |
276 | //Duplicate code!
277 |
278 | /**
279 | * @return string
280 | */
281 | protected function makeImageName(): string
282 | {
283 | return sprintf('served/%s_%s', $this->projectName(), $this->name());
284 | }
285 |
286 | protected function isWindows()
287 | {
288 | return Str::startsWith(PHP_OS,'WIN');
289 | }
290 |
291 | }
292 |
--------------------------------------------------------------------------------
/src/Containers/MailhogContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
25 | 'alias' => $this->name(),
26 | 'port' => $this->port(),
27 | 'container_name' => $this->makeContainerName(),
28 | 'image_name' => $this->makeImageName(),
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Containers/MemcachedContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
18 | 'alias' => $this->name(),
19 | 'container_name' => $this->makeContainerName(),
20 | 'image_name' => $this->makeImageName(),
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Containers/MysqlContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
34 | 'container_name' => $this->makeContainerName(),
35 | 'image_name' => $this->makeImageName(),
36 | 'port' => $this->port(),
37 | 'alias' => $this->name(),
38 | 'volume' => $this->volume(),
39 | ];
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | protected function volume(): string
46 | {
47 | if ($volume = Arr::get($this->config, 'volume')) {
48 | return $volume;
49 | }
50 |
51 | return $this->projectName() . '_' . $this->name();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Containers/NginxContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
29 | 'container_name' => $this->makeContainerName(),
30 | 'image_name' => $this->makeImageName(),
31 | 'port' => $this->port(),
32 | 'ssl_port' => $this->sslPort(),
33 | 'local_dir' => base_path(),
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Containers/PhpContainer.php:
--------------------------------------------------------------------------------
1 | dockerRunCommand .= $this->volumes();
20 | }
21 |
22 | /**
23 | * @return array
24 | */
25 | protected function env(): array
26 | {
27 | return [
28 | 'network' => $this->projectName(),
29 | 'container_name' => $this->makeContainerName(),
30 | 'image_name' => $this->makeImageName(),
31 | 'local_dir' => base_path(),
32 | ];
33 | }
34 |
35 | /**
36 | * @return string
37 | */
38 | protected function volumes(): string
39 | {
40 | $volumes = Arr::get($this->config, 'volumes', []);
41 | if (!$volumes) {
42 | return '';
43 | }
44 |
45 | return ' ' . collect($volumes)->map(function ($item) {
46 | return '-v="' . $item . '"';
47 | })->implode(' ');
48 | }
49 |
50 | public function enableXdebug(): void
51 | {
52 | $this->shell->exec('docker exec --user root ' . $this->makeContainerName() . ' mv /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.old /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini');
53 | $this->kill();
54 | }
55 |
56 | public function disableXdebug(): void
57 | {
58 | $this->shell->exec('docker exec --user root ' . $this->makeContainerName() . ' mv /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.old');
59 | $this->kill();
60 | }
61 |
62 | public function kill(): void
63 | {
64 | $this->shell->exec('docker exec --user root ' . $this->makeContainerName() . ' /bin/bash -c "kill USR2 1"');
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Containers/PostgresContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
34 | 'container_name' => $this->makeContainerName(),
35 | 'image_name' => $this->makeImageName(),
36 | 'port' => $this->port(),
37 | 'alias' => $this->name(),
38 | 'volume' => $this->volume(),
39 | ];
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | protected function volume(): string
46 | {
47 | if ($volume = Arr::get($this->config, 'volume')) {
48 | return $volume;
49 | }
50 |
51 | return $this->projectName() . '_' . $this->name();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Containers/RedisContainer.php:
--------------------------------------------------------------------------------
1 | $this->projectName(),
18 | 'alias' => $this->name(),
19 | 'container_name' => $this->makeContainerName(),
20 | 'image_name' => $this->makeImageName(),
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Docker/Docker.php:
--------------------------------------------------------------------------------
1 | shell = $shell;
26 | }
27 |
28 | /**
29 | * @return void
30 | * @throws DockerNotInstalledException
31 | */
32 | public function verifyDockerIsInstalled(): void
33 | {
34 | try {
35 | $this->version();
36 |
37 | } catch (ProcessFailedException $e) {
38 | throw new DockerNotInstalledException('Docker is missing!');
39 | }
40 | }
41 |
42 | /**
43 | * @return void
44 | * @throws DockerNotRunningException
45 | */
46 | public function verifyDockerDemonIsRunning(): void
47 | {
48 | try {
49 | $this->shell->exec('docker info');
50 |
51 | } catch (ProcessFailedException $e) {
52 | throw new DockerNotRunningException('Docker isn\'t running');
53 | }
54 | }
55 |
56 | /**
57 | * @return string
58 | */
59 | public function version(): string
60 | {
61 | return $this->shell->exec('docker version --format="{{json .Client.Version}}"');
62 | }
63 |
64 | /**
65 | * @param string $name
66 | * @return void
67 | */
68 | public function ensureNetworkExists(string $name): void
69 | {
70 | try {
71 | $this->shell->exec('docker network inspect "${:name}"', ['name' => $name]);
72 |
73 | } catch (ProcessFailedException $e) {
74 | //Make network
75 |
76 | $this->shell->exec('docker network create "${:name}"', ['name' => $name]);
77 | }
78 | }
79 |
80 | public function removeNetwork(string $name): void
81 | {
82 | $this->shell->exec('docker network rm ' . $name);
83 | }
84 |
85 | /**
86 | * @return \Illuminate\Support\Collection
87 | */
88 | public function listContainers()
89 | {
90 | $name = $this->makeName();
91 | $containers = $this->shell->exec('docker ps --all --filter "name=' . $name . '" --format "{{.ID}}|{{.Names}}|{{.Image}}|{{.Status}}|{{.Ports}}"');
92 | $formatted = collect(explode("\n", $containers))->filter()->map(function ($row) {
93 | return explode('|', $row);
94 | })->reverse();
95 |
96 | return $formatted->prepend([
97 | 'ID', 'Name', 'Image', 'Status', 'Used ports'
98 | ]);
99 |
100 | }
101 |
102 | public function getUsedPort($name, $internalPort)
103 | {
104 | $name = $this->makeName($name);
105 | try {
106 | $usedPort = $this->shell->exec('docker port ' . $name . ' ' . $internalPort);
107 |
108 | } catch (ProcessFailedException $e) {
109 | return null;
110 | }
111 |
112 | return intval(Str::afterLast(trim($usedPort), ':'));
113 | }
114 |
115 | protected function makeName($name = '')
116 | {
117 | return sprintf('served_%s_%s', app('served.name'), $name);
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/src/Docker/DockerFileBuilder.php:
--------------------------------------------------------------------------------
1 | fileStructure[] = sprintf('FROM %1$s:%2$s', $image, $tag);
20 |
21 | return $this;
22 | }
23 |
24 | /**
25 | * @return $this
26 | */
27 | public function newLine(): self
28 | {
29 | $this->fileStructure[] = '';
30 |
31 | return $this;
32 | }
33 |
34 | /**
35 | * @param string $comment
36 | * @param false $newLineBefore
37 | * @return $this
38 | */
39 | public function comment(string $comment, $newLineBefore = false): self
40 | {
41 | if ($newLineBefore) {
42 | $this->newLine();
43 | }
44 |
45 | $this->fileStructure[] = '# ' . str_replace("\n", "\n# ", $comment);
46 |
47 | return $this;
48 | }
49 |
50 | /**
51 | * @param string $arg
52 | * @return $this
53 | */
54 | public function arg(string $arg): self
55 | {
56 | $this->fileStructure[] = sprintf('ARG %s', $arg);
57 |
58 | return $this;
59 | }
60 |
61 | /**
62 | * @param string|array $command
63 | * @return $this
64 | */
65 | public function run($command, $delimiter = '&&'): self
66 | {
67 | if (is_array($command)) {
68 | $command = implode(' \\' . "\n $delimiter ", $command);
69 | }
70 |
71 | $this->fileStructure[] = sprintf('RUN %s', $command);
72 |
73 | return $this;
74 | }
75 |
76 | /**
77 | * @param string $name
78 | * @param string $value
79 | * @return $this
80 | */
81 | public function env(string $name, string $value): self
82 | {
83 | $this->fileStructure[] = sprintf('ENV %1$s=%2$s', $name, $value);
84 |
85 | return $this;
86 | }
87 |
88 | /**
89 | * @param $source
90 | * @param string $target
91 | * @param string|null $from
92 | * @return $this
93 | */
94 | public function copy($source, string $target, ?string $from = null): self
95 | {
96 | if (is_array($source)) {
97 | $source = implode(' ', $source);
98 | $target = rtrim($target, '/') . '/';
99 | }
100 | $from = $from ? ' --from=' . $from : null;
101 | $this->fileStructure[] = sprintf('COPY%3$s %1$s %2$s', $source, $target, $from);
102 |
103 | return $this;
104 | }
105 |
106 | /**
107 | * @param string $workdir
108 | * @return $this
109 | */
110 | public function workdir(string $workdir)
111 | {
112 | $this->fileStructure[] = sprintf('WORKDIR %s', $workdir);
113 | return $this;
114 | }
115 |
116 | /**
117 | * @param string $workdir
118 | * @return $this
119 | */
120 | public function cmd(array $cmd)
121 | {
122 | $items = array_map(function($item) {
123 | return '"' . $item . '"';
124 | }, $cmd);
125 |
126 | $this->fileStructure[] = sprintf('CMD [ %s ]', implode(', ', $items));
127 | return $this;
128 | }
129 |
130 | /**
131 | * @return string
132 | */
133 | public function __toString(): string
134 | {
135 | return implode("\n", $this->fileStructure);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/Exceptions/DockerNotInstalledException.php:
--------------------------------------------------------------------------------
1 | copyDockerFile(__DIR__ . '/stubs/localhost.crt', 'localhost.crt');
33 | $this->copyDockerFile(__DIR__ . '/stubs/localhost.key', 'localhost.key');
34 | }
35 |
36 | /**
37 | * @return array
38 | */
39 | protected function prepareEnv(): array
40 | {
41 | return [
42 | 'imagename' => $this->makeImageName(),
43 | 'dockerfile' => $this->findDockerFile(),
44 | ];
45 | }
46 |
47 | /**
48 | * @return string
49 | */
50 | public function writeDockerFile(): string
51 | {
52 | $command = $this->getBaseDockerFile()
53 | ->env('WEB_PHP_SOCKET', 'served_php:9000')
54 | ->env('WEB_DOCUMENT_ROOT', '/app/public')
55 | ->env('WEB_PHP_TIMEOUT', '60')
56 | ->copy($this->storageDirectory(true) . 'localhost.key', '/opt/docker/etc/httpd/ssl/server.key')
57 | ->copy($this->storageDirectory(true) . 'localhost.crt', '/opt/docker/etc/httpd/ssl/server.crt');
58 |
59 | return (string)$command;
60 |
61 | }
62 |
63 | public function imageTag(): string
64 | {
65 | return $this->tag;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Images/Image.php:
--------------------------------------------------------------------------------
1 | config = $config;
68 | $this->shell = $shell;
69 | $this->dockerFileBuilder = app(DockerFileBuilder::class);
70 | $this->name = $name;
71 | $this->parseConfig();
72 | }
73 |
74 | /**
75 | * @return $this
76 | */
77 | public function prepareBuild(): self
78 | {
79 | $this->prepareConfFiles();
80 | $dockerFile = $this->writeDockerFile();
81 | $this->storeDockerfile($dockerFile);
82 |
83 | return $this;
84 | }
85 |
86 | protected function getBaseDockerFile()
87 | {
88 | $command = $this->dockerFileBuilder->from($this->imageName(), $this->imageTag());
89 |
90 | if ($proxyHttp = config('served.proxy.http', false)) {
91 | $command->env('http_proxy', $proxyHttp);
92 | }
93 |
94 | if ($proxyHttps = config('served.proxy.https', false)) {
95 | $command->env('https_proxy', $proxyHttps);
96 | }
97 |
98 | return $command;
99 | }
100 |
101 | /**
102 | * @return void
103 | */
104 | public function parseConfig(): void
105 | {
106 | foreach ($this->config as $key => $value) {
107 | if ($key === 'version') {
108 | $this->setImageTag($value);
109 | }
110 |
111 | if ($key === 'alias') {
112 | $this->setAlias($value);
113 | }
114 | }
115 | }
116 |
117 | /**
118 | * @param boolean $noCache
119 | * @return void
120 | */
121 | public function build($noCache): void
122 | {
123 | $this->shell->run(
124 | $this->prepareBuildCommand($noCache),
125 | $this->prepareEnv()
126 | );
127 | }
128 |
129 | protected function prepareBuildCommand($noCache)
130 | {
131 | return $this->buildCommand . ($noCache ? $this->buildFlags : '');
132 | }
133 |
134 | /**
135 | * @return array
136 | */
137 | protected function prepareEnv()
138 | {
139 | return [];
140 | }
141 |
142 | protected function prepareConfFiles()
143 | {
144 | //
145 | }
146 |
147 | /**
148 | * @return bool
149 | */
150 | public function imageExists(): bool
151 | {
152 | try {
153 | $this->shell->exec(sprintf('docker inspect image %s', $this->makeImageName()));
154 | return true;
155 | } catch (ProcessFailedException $e) {
156 | return false;
157 | }
158 | }
159 |
160 | /**
161 | * @return void
162 | */
163 | public function remove(): void
164 | {
165 | $this->shell->exec(sprintf('docker rmi %s -f', $this->makeImageName()));
166 | }
167 |
168 | /**
169 | * @return string
170 | */
171 | protected function makeImageName(): string
172 | {
173 | return sprintf('served/%s_%s', $this->projectName(), $this->name());
174 | }
175 |
176 | /**
177 | * @return string
178 | */
179 | public function imageName(): string
180 | {
181 | return sprintf('%s/%s', $this->library, $this->image);
182 | }
183 |
184 | /**
185 | * @return string
186 | */
187 | public function imageTag(): string
188 | {
189 | return sprintf('%s%s', $this->tag, $this->tagAddition);
190 | }
191 |
192 | /**
193 | * @param $tag
194 | * @return $this
195 | */
196 | public function setImageTag($tag): self
197 | {
198 | if ($tag) {
199 | $this->tag = $tag;
200 | }
201 |
202 | return $this;
203 | }
204 |
205 | /**
206 | * @param string $alias
207 | * @return $this
208 | */
209 | public function setAlias(string $alias): self
210 | {
211 | if ($alias) {
212 | $this->alias = $alias;
213 | }
214 |
215 | return $this;
216 | }
217 |
218 | /**
219 | * @return string
220 | */
221 | protected function projectName(): string
222 | {
223 | return app('served.name');
224 | }
225 |
226 | /**
227 | * @return string
228 | */
229 | public function simpleName()
230 | {
231 | return strtolower(class_basename($this));
232 | }
233 |
234 | /**
235 | * @return string
236 | */
237 | public function name(): string
238 | {
239 | return $this->name;
240 | }
241 |
242 | /**
243 | * @param string $content
244 | * @return void
245 | */
246 | protected function storeDockerfile(string $content): void
247 | {
248 | $storagePath = $this->storageDirectory();
249 | file_put_contents($storagePath . 'Dockerfile', $content);
250 | }
251 |
252 | /**
253 | * @param string $filePath
254 | * @param string $targetName
255 | * @return void
256 | */
257 | protected function copyDockerFile(string $filePath, string $targetName): void
258 | {
259 | $storagePath = $this->storageDirectory();
260 | copy($filePath, $storagePath . $targetName);
261 | }
262 |
263 | /**
264 | * @return string
265 | */
266 | protected function findDockerFile(): string
267 | {
268 | return $this->storageDirectory() . 'Dockerfile';
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/src/Images/ImageInterface.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
42 | 'uid' => getmyuid(),
43 | 'dockerfile' => $this->findDockerFile(),
44 | ];
45 | }
46 |
47 | /**
48 | * @return string
49 | */
50 | public function writeDockerFile(): string
51 | {
52 | return (string) $this->getBaseDockerFile();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Images/MemcachedImage.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
37 | 'dockerfile' => $this->findDockerFile(),
38 | ];
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function writeDockerFile(): string
45 | {
46 | return (string) $this->getBaseDockerFile();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Images/MysqlImage.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
30 | 'uid' => getmyuid(),
31 | 'dockerfile' => $this->findDockerFile()
32 | ];
33 | }
34 |
35 | /**
36 | * @return string
37 | */
38 | public function writeDockerFile(): string
39 | {
40 | $command = $this->getBaseDockerFile()
41 | ->newLine()
42 | ->comment('Setting env vars for mysql init')
43 | ->env('MYSQL_ROOT_PASSWORD', 'password')
44 | ->env('MYSQL_DATABASE', 'laravel')
45 | ->env('MYSQL_USER', 'laravel')
46 | ->env('MYSQL_PASSWORD', 'password');
47 |
48 | return (string)$command;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Images/NginxImage.php:
--------------------------------------------------------------------------------
1 | copyDockerFile(__DIR__ . '/stubs/nginx.conf', 'default.conf');
28 | $this->copyDockerFile(__DIR__ . '/stubs/localhost.crt', 'localhost.crt');
29 | $this->copyDockerFile(__DIR__ . '/stubs/localhost.key', 'localhost.key');
30 | }
31 |
32 | /**
33 | * @return array
34 | */
35 | protected function prepareEnv()
36 | {
37 | return [
38 | 'imagename' => $this->makeImageName(),
39 | 'uid' => getmyuid(),
40 | 'dockerfile' => $this->findDockerFile(),
41 | ];
42 | }
43 |
44 | /**
45 | * @return string
46 | */
47 | public function writeDockerFile(): string
48 | {
49 | $command = $this->getBaseDockerFile()
50 | ->newLine()
51 | ->comment('Copy in new nginx config')
52 | // ->copy('storage/served/nginx/default.conf', '/etc/nginx/conf.d/default.conf');
53 | ->copy($this->storageDirectory(true) . 'default.conf', '/etc/nginx/conf.d/default.conf')
54 | ->copy($this->storageDirectory(true) . 'localhost.key', '/etc/nginx/ssl/server.key')
55 | ->copy($this->storageDirectory(true) . 'localhost.crt', '/etc/nginx/ssl/server.crt');
56 |
57 | return (string)$command;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Images/PhpImage.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
36 | 'uid' => getmyuid() <= 1 ? 1000 : getmyuid(),
37 | 'dockerfile' => $this->findDockerFile(),
38 | ];
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function writeDockerFile(): string
45 | {
46 | $command = $this->getBaseDockerFile();
47 |
48 | $command->comment('disable warnings for "dangerous" messages', true)
49 | ->env('APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE', '1');
50 |
51 | $runInstalls = [
52 | 'apt-get update',
53 | 'apt-get install -y unzip zip gnupg',
54 | 'rm -rf /var/lib/apt/lists/*',
55 | ];
56 |
57 | $command
58 | ->comment('Adding linux packages', true)
59 | ->run($runInstalls);
60 |
61 | $gpgOptions = '';
62 | if ($proxyHttp = config('served.proxy.http', false)) {
63 | $gpgOptions .= '--keyserver-options http-proxy=${http_proxy}';
64 | }
65 |
66 | $command
67 | ->comment('Installing packages for sql dump')
68 | ->run([
69 | 'set -ex;',
70 | 'key=\'8C718D3B5072E1F5\';',
71 | 'export GNUPGHOME="$(mktemp -d)";',
72 | 'gpg --batch ' . $gpgOptions . ' --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key";',
73 | 'gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg;',
74 | 'gpgconf --kill all;',
75 | 'rm -rf "$GNUPGHOME";',
76 | 'apt-key list > /dev/null',
77 | ], '')
78 | ->newLine()
79 | ->run([
80 | 'echo "deb http://repo.mysql.com/apt/debian/ buster mysql-8.0" > /etc/apt/sources.list.d/mysql.list',
81 | 'apt-get update',
82 | 'apt-get install -y mysql-community-client postgresql-client sqlite3',
83 | 'rm -rf /var/lib/apt/lists/*'
84 | ]);
85 |
86 |
87 | $command
88 | ->comment('add development php.ini file', true)
89 | ->run('mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"');
90 |
91 | $command
92 | ->comment("add a local user with the same uid as the local\nprepare empty composer config directory\nensure user owns its home directory")
93 | ->arg('uid')
94 | ->run([
95 | 'useradd -G root -u $uid -d /home/served served',
96 | 'mkdir -p /home/served/.composer',
97 | 'chown -R served:served /home/served'
98 | ])
99 | ->comment("add composer\nset composer to use https", true)
100 | ->run([
101 | 'curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer',
102 | 'runuser -l served -c "composer config --global repos.packagist composer https://packagist.org"',
103 | ]);
104 |
105 | if (Arr::get($this->config, 'npm', false)) {
106 | $command
107 | ->comment('Adding NPM')
108 | ->run([
109 | 'curl -sL https://deb.nodesource.com/setup_12.x | bash',
110 | 'apt-get install -y nodejs',
111 | 'curl -L https://www.npmjs.com/install.sh | sh',
112 | ]);
113 | }
114 |
115 | $modules = Arr::get($this->config, 'modules', []);
116 |
117 | if (Arr::get($this->config, 'xdebug.enabled') && !in_array('xdebug', $modules)) {
118 | $modules[] = 'xdebug';
119 | }
120 |
121 | if ($modules) {
122 | if ($proxyHttp = config('served.proxy.http', false)) {
123 | $command
124 | ->comment('setting proxy for pear')
125 | ->run('pear config-set http_proxy ${http_proxy}');
126 | }
127 | $command
128 | ->comment('Adding php packages', true)
129 | ->copy('/usr/bin/install-php-extensions', '/usr/bin/', 'mlocati/php-extension-installer')
130 | ->run('install-php-extensions ' . implode(' ', $modules));
131 |
132 | }
133 |
134 | if (in_array('xdebug', $modules) && Arr::get($this->config, 'xdebug.enabled')) {
135 | $command
136 | ->comment('Adding xdebug', true)
137 | ->run([
138 | 'echo "[xdebug]" >> "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"',
139 | 'echo "xdebug.remote_enable = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"',
140 | 'echo "xdebug.remote_port = ' . Arr::get($this->config, 'xdebug.port', 9001) . '" >> "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"',
141 | 'echo "xdebug.remote_connect_back = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"',
142 | 'echo "xdebug.remote_autostart = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini"',
143 | ]);
144 | }
145 |
146 | $command
147 | ->comment('Set work dir', true)
148 | ->workdir('/app');
149 |
150 | return (string)$command;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/Images/PostgresImage.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
30 | 'dockerfile' => $this->findDockerFile()
31 | ];
32 | }
33 |
34 | /**
35 | * @return string
36 | */
37 | public function writeDockerFile(): string
38 | {
39 | $command = $this->getBaseDockerFile()
40 | ->newLine()
41 | ->comment('Setting env vars for postgres init')
42 | ->env('POSTGRES_DB', 'laravel')
43 | ->env('POSTGRES_USER', 'laravel')
44 | ->env('POSTGRES_PASSWORD', 'password');
45 |
46 | return (string)$command;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Images/RedisImage.php:
--------------------------------------------------------------------------------
1 | $this->makeImageName(),
37 | 'uid' => getmyuid(),
38 | 'dockerfile' => $this->findDockerFile(),
39 | ];
40 | }
41 |
42 | /**
43 | * @return string
44 | */
45 | public function writeDockerFile(): string
46 | {
47 | $command = $this->getBaseDockerFile()
48 | ->cmd(['redis-server']);
49 |
50 | return (string) $command;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Images/stubs/localhost.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFJTCCAw2gAwIBAgIUJUn5rdtwaQhuVMVxlrNM/AiVrXowDQYJKoZIhvcNAQEL
3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTAwMTA5NDkxMVoXDTMwMDky
4 | OTA5NDkxMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
5 | AAOCAg8AMIICCgKCAgEA15Su38lrcKIvMnCTviDxUGZkPoFG1QaMAxD++PsDkYM8
6 | Hk/3l4QKowhqGEV8YJOfQa5bptdyRvm0znwro4rVdDa9KJ3Bz5YqM+7IMe2QX5Sd
7 | IGbyGW4pqi8+Ss10GfpfFWp0Xm01np1eFvCMhGdhjZEI5BL2wl8cvCnv8iUUDvqC
8 | BE8VkiQIr8ZnGm9ouDG2uwpW0+cUJS+hOGb8tulxoau/IVcUc/apMBsSiWDvhhb5
9 | P5Pj0fGuF0WUb1ayJHPo55/96DdEpJE9nFzEMXi/zMqGvwteRzKS6WP5LhRdKIAJ
10 | DNa8V3dzGs6oyr6lumKqjKmqHiQmDouuZoRnO1xc25C7XT8SCpIUEy47nRlVmYeX
11 | /fGz6K8ZnU4lxKQS9hsmfYPMWO0ntfnyGrGTgJszSZz6giPE3HmDdY4oJ88KhNhS
12 | MmLtDa5xFIcMbIEazlxiSWM/y84A3XgSMTcyhuQcTizKLzvqD2toQZebOkpDSCyZ
13 | GJc9UGSDBeqOu7F7eXp8FRi3e04MCqtNm9AbYcJCQcVPzcW/13j3z/QESXQuMpdU
14 | s7p7+rknHwlKJHE37gzbEkJZ6qYIJqToGXi0fBE59tKsv8XwwaJete8uA8heIpYE
15 | ch4YaFhHLOJZi6iQX+cCkA50VyH7kZdggL3BqaC9SUIrWV90uaB42ErgZoIHqTcC
16 | AwEAAaNvMG0wHQYDVR0OBBYEFGnfcwb/YmVY8C3APuYCvdKfPhEJMB8GA1UdIwQY
17 | MBaAFGnfcwb/YmVY8C3APuYCvdKfPhEJMA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0R
18 | BBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4ICAQA4xKwwyL9B
19 | +Omyp48qiIGhEkmN7gkMjCk3zXkBTRIliytUcL/2SYJP9DqRXJzuD+HOoROesa93
20 | Jq1Zkp7C+6EqXLKbltW+0KNBQiIzuvTqXhK8LoQsiTv60jzWY9RDSwhn26BHZN8s
21 | zPE3/XQJ4rcwNz/V4EB7AbjSR9Y0hQrPhqNNJ17v4yWx/bWO2zSN+Uu7LZQ/2fFh
22 | sTznB8io/ZwoUAmtDzv1qWZajihmsK0d5kJU9T+7Mz3qk1LeaxS/BzHnXek7ul1f
23 | zZ5r6OD0Znlc9BMddVVT0mOAJWRyfSyZjXw8zVCk5S/3WPsFeTALCl/+hQeyRZGH
24 | CtLo0CtpHCVGX3+uP1/U21NsfG9gfCINpBRc68BJcPZJbDXLLVVen5jLEDNN7JGd
25 | ok3rQ49kpqk0ATAk3GtOEJRex8MyryuKEKKvJf5yIA4e6uhBx6pK25cFVJdOygE5
26 | m2OGIcsF7tbR1kvBrcg+k0y4rwK0wJiQeOJGMdLnQ6ZkNBZxkK2/2ggDhcb4f+1v
27 | 2HZ4E+zc5NoKo2f+m41QtKOWecgYDILbPX2uxW/83YGC6qxeEtu5zSMSFjwwbOLL
28 | EBooISukaRW+IZBO18tQm52j8qYFAPB7+fbi6n2NNDyBwLcaeirow2hbCj8xkS61
29 | SSM7Sq9IZjkBeoms4sIfYjxvAX2WUtJhhA==
30 | -----END CERTIFICATE-----
31 |
--------------------------------------------------------------------------------
/src/Images/stubs/localhost.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDXlK7fyWtwoi8y
3 | cJO+IPFQZmQ+gUbVBowDEP74+wORgzweT/eXhAqjCGoYRXxgk59Brlum13JG+bTO
4 | fCujitV0Nr0oncHPlioz7sgx7ZBflJ0gZvIZbimqLz5KzXQZ+l8VanRebTWenV4W
5 | 8IyEZ2GNkQjkEvbCXxy8Ke/yJRQO+oIETxWSJAivxmcab2i4Mba7ClbT5xQlL6E4
6 | Zvy26XGhq78hVxRz9qkwGxKJYO+GFvk/k+PR8a4XRZRvVrIkc+jnn/3oN0SkkT2c
7 | XMQxeL/Myoa/C15HMpLpY/kuFF0ogAkM1rxXd3MazqjKvqW6YqqMqaoeJCYOi65m
8 | hGc7XFzbkLtdPxIKkhQTLjudGVWZh5f98bPorxmdTiXEpBL2GyZ9g8xY7Se1+fIa
9 | sZOAmzNJnPqCI8TceYN1jignzwqE2FIyYu0NrnEUhwxsgRrOXGJJYz/LzgDdeBIx
10 | NzKG5BxOLMovO+oPa2hBl5s6SkNILJkYlz1QZIMF6o67sXt5enwVGLd7TgwKq02b
11 | 0BthwkJBxU/Nxb/XePfP9ARJdC4yl1Szunv6uScfCUokcTfuDNsSQlnqpggmpOgZ
12 | eLR8ETn20qy/xfDBol617y4DyF4ilgRyHhhoWEcs4lmLqJBf5wKQDnRXIfuRl2CA
13 | vcGpoL1JQitZX3S5oHjYSuBmggepNwIDAQABAoICAHCdR9i5RDm7T0JfEp6gYM6q
14 | HjWUnKbNW7iCWV9A6PVLg80l4uWwYUoXLCzvp3BfzTKnXVNDenvfF3dB4B33eVfS
15 | /G9KMaM6A2PLmaKTQfbcEFSL0m48YOF4+mZi+wJTCvaJ/K4TCI6KEEuVbyH/SzOD
16 | jwxtZ5/TxZP5qFFq0xab/+02TsNftXX1A4kIp8CIn7cHSKI7NQfT4Lkw+1Slj+lv
17 | aVGGRrXpJSpvCfjfvV/jgmKW48yZHmMjws2CkV5/eiv9JMr4jBAXmwKiZw6c0Dyv
18 | k0IbMy2oGpx20AUlOCDe+VtOlWZvjJ51VDFM9A/wWL1QKADEy2iPyRPemHqm3g4S
19 | xQD9BjivxUkc9QacLoRunUwfrSe1lL+yyuBuiQWDWK1PEiupPHHL+/gt0d4kuNof
20 | IOZ5dV8irczxU4CLnOa1jI4El37yea+UOlAESUO1a7pd8C5iQuh//t/8H9993Fi6
21 | /gz68/0WbbuVCxRXDEyBtZUB421vpmVF2si2BdZdi/6SWuIbmQbTlBo9J4UPe5P0
22 | 5QpQCgQYi9Otw4U7XQ9h2MuH7TjbKHbY+NSu6q8SHPobCKHzRDU8+rx/wTh0nmKA
23 | B54cNCOq7G5qnZ/6gNa24lcpA1PFdj9b/4AGLkyK0Ww3GSo3NpZ7Ug0QPxsJWm9j
24 | pvblXJ0RGw8ANEOvOugBAoIBAQD3G0TtT/eyqpYCpXL5R5k6DoSo7Zhu+F/RFUJE
25 | LVz0ih6+Cwz6MgDTjt+zyKJxXrozSYim7qO7R1jPfaGC6GqxY9s+IHvqPFri4vhl
26 | /svVURjOEO+WmdI2qxxwSaCXXICriHjHld2bA0O1g7y5Q/8vk2vPOY5Ne4dFTgLm
27 | 8tA2/qRp+8NAqNpM0Oc0vFmtZIHmazvWpQ80ww1wwsxTh8TKUOa5BsFrQs0Gbpe5
28 | b8uvvOSV/ocJHD1erdcliUBRWcjkmgS9ArosFrI1obel0//fTAgcL8j9pDjPslzG
29 | sQrwzL0iNXcGEG0wrcnEyA7BDvXA7CcJkP2Dfb3IYKu8iN03AoIBAQDfVvMeEgru
30 | cUgXbt1m9SIWFY5Vkw7pfzfaj8shOulJcM67HFUg8IZ6bnnIjuOly84RoigbzKsM
31 | GdJ/WzlpGT0XlbH3lb0ZnorFgYRT/YnFqtvRVlcYN9x9kM6ZOM85vA1PUIilVKaC
32 | IkpSeiBXMnN4IoLbjua68TvtZ60zvcmcAja8KteNZ7efJ7FMwnnsI0JYk/N84yl1
33 | LaWVnp+4aneHseq3f19sQawZfNT2TOECijFK21sHgBne5J7dlW413jJp28xVCzF4
34 | sDql+n/suUfyirHnNaUJ6CdUsoi+muIBer0IGOidqoHKi1G25KC5srPcugtKtsxG
35 | URqmXhxMvZQBAoIBAB99uisEJez/EF8F9sEN/tkHQKDGpsZ9oLhknS1TGqWPdJuD
36 | jQPVm4Vaj+e5ifoouFIQ7PlZMESNsyO+PvcP54jz0Nz6BtCzIGIJyt40uoVU8HRS
37 | dDYdJE0TQWyN9YlUoJE7syi8UKGQqPBY+ZQitkK55uNh0mDNfU+3wWbtStu3V/yp
38 | uRhkbG2dsdlmp4cRZ/yVberM3kM7GFtmd+OtScb+yGiME9o3iSlorq1TMgITcI4t
39 | AciHcMrAHMsL0saLSq7XcgMkddVojw2GroDTo6gxaFcvP84TP6o4cNphdaN6dCAH
40 | 8EM1lLS/cRdC555y6Z7Mea0ebTB0tdrzdu9wAcECggEBAJS+1Cyy15T23Yy9ybdI
41 | i+spcCKOTuA0Wn62RhNbqQPAne8Ab7IAf5ALBBEPGY7SrewQk6XwKftlN0ya9SGK
42 | LaYHjP/YOplVfhcMq5VExv1fTged+WOn0LHQP8jMjTdmh3bLrDZwqnUBYX6M1/07
43 | HKxmT8Dq68CV6dOzuSc8v4mn78xivCzxZtoZFXyKCam70fQslX4XzQS94gpEGxw3
44 | zGQTmr+blXIESxquiSeBDFskrq+saHQWXSSWHzh0zXITCoB2YyBA1DINLQJeU9TV
45 | kZV3ygSzNbfjZk6CmZBYly1lEYDTFhnr9YVwRHwKyQDkg+X+AodAN8ydN6KWC0MR
46 | AAECggEBAJyxTnVZFSttq99jY38+tI2KnAAmFtWYiG7EWFvFlh8gslI7jlaD2Q9J
47 | H6NZT3mmKzK0QSYPzGuKLlzsRsFGSemPKqc52TPS/81vknejIv7OIYwPAH2B6PzJ
48 | 8tVUMslEEMXf0LiT538bMgb+lJvMzJRzUvbusZwnGnaXl+ZqFwpkAxa65AjeQC45
49 | mJIJ9v67ka841gszYiFrNJA0wc1DVRVtT0lC3PaewQR/1mdDfZo0eHjj8ry7m+qZ
50 | sCeyZlFTS7kk53Mb0j3Y0YwP3AiciaM7V2EBAYj9PeIIYmq1xkkJkrVjdrDb5cR2
51 | pxldlOxgBdmXQTp/xlAxTR8208AyRxU=
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/src/Images/stubs/my-httpd-vhosts.conf:
--------------------------------------------------------------------------------
1 | # Virtual Hosts
2 | #
3 | # Required modules: mod_log_config
4 |
5 | # If you want to maintain multiple domains/hostnames on your
6 | # machine you can setup VirtualHost containers for them. Most configurations
7 | # use only name-based virtual hosts so the server doesn't need to worry about
8 | # IP addresses. This is indicated by the asterisks in the directives below.
9 | #
10 | # Please see the documentation at
11 | #
12 | # for further details before you try to setup virtual hosts.
13 | #
14 | # You may use the command line option '-S' to verify your virtual host
15 | # configuration.
16 |
17 | #
18 | # VirtualHost example:
19 | # Almost any Apache directive may go into a VirtualHost container.
20 | # The first VirtualHost section is used for all requests that do not
21 | # match a ServerName or ServerAlias in any block.
22 | #
23 |
24 | ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://served_php:9000${APACHE_ROOT_DIR}/public/$1
25 |
26 | DocumentRoot ${APACHE_ROOT_DIR}/public
27 |
28 |
29 | Options Indexes FollowSymLinks
30 | AllowOverride All
31 | Require all granted
32 |
33 |
34 | ErrorLog ${APACHE_ROOT_DIR}/logs/error.log
35 | CustomLog ${APACHE_ROOT_DIR}/logs/access.log common
36 |
37 |
38 |
39 | ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://served_php:9000${APACHE_ROOT_DIR}/public/$1
40 |
41 | DocumentRoot ${APACHE_ROOT_DIR}/public
42 |
43 |
44 | Options Indexes FollowSymLinks
45 | AllowOverride All
46 | Require all granted
47 |
48 |
49 | SSLEngine on
50 | SSLCertificateFile /etc/apache2/ssl/localhost.crt
51 | SSLCertificateKeyFile /etc/apache2/ssl/localhost.key
52 |
53 | ErrorLog ${APACHE_ROOT_DIR}/logs/error.log
54 | CustomLog ${APACHE_ROOT_DIR}/logs/access.log common
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/Images/stubs/my-httpd.conf:
--------------------------------------------------------------------------------
1 | #
2 | # This is the main Apache HTTP server configuration file. It contains the
3 | # configuration directives that give the server its instructions.
4 | # See for detailed information.
5 | # In particular, see
6 | #
7 | # for a discussion of each configuration directive.
8 | #
9 | # Do NOT simply read the instructions in here without understanding
10 | # what they do. They're here only as hints or reminders. If you are unsure
11 | # consult the online docs. You have been warned.
12 | #
13 | # Configuration and logfile names: If the filenames you specify for many
14 | # of the server's control files begin with "/" (or "drive:/" for Win32), the
15 | # server will use that explicit path. If the filenames do *not* begin
16 | # with "/", the value of ServerRoot is prepended -- so "logs/access_log"
17 | # with ServerRoot set to "/usr/local/apache2" will be interpreted by the
18 | # server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
19 | # will be interpreted as '/logs/access_log'.
20 |
21 | #
22 | # ServerRoot: The top of the directory tree under which the server's
23 | # configuration, error, and log files are kept.
24 | #
25 | # Do not add a slash at the end of the directory path. If you point
26 | # ServerRoot at a non-local disk, be sure to specify a local disk on the
27 | # Mutex directive, if file-based mutexes are used. If you wish to share the
28 | # same ServerRoot for multiple httpd daemons, you will need to change at
29 | # least PidFile.
30 | #
31 | ServerRoot "/usr/local/apache2"
32 |
33 | #
34 | # Mutex: Allows you to set the mutex mechanism and mutex file directory
35 | # for individual mutexes, or change the global defaults
36 | #
37 | # Uncomment and change the directory if mutexes are file-based and the default
38 | # mutex file directory is not on a local disk or is not appropriate for some
39 | # other reason.
40 | #
41 | # Mutex default:logs
42 |
43 | #
44 | # Listen: Allows you to bind Apache to specific IP addresses and/or
45 | # ports, instead of the default. See also the
46 | # directive.
47 | #
48 | # Change this to Listen on specific IP addresses as shown below to
49 | # prevent Apache from glomming onto all bound IP addresses.
50 | #
51 | #Listen 12.34.56.78:80
52 | Listen 80
53 |
54 | #
55 | # Dynamic Shared Object (DSO) Support
56 | #
57 | # To be able to use the functionality of a module which was built as a DSO you
58 | # have to place corresponding `LoadModule' lines at this location so the
59 | # directives contained in it are actually available _before_ they are used.
60 | # Statically compiled modules (those listed by `httpd -l') do not need
61 | # to be loaded here.
62 | #
63 | # Example:
64 | # LoadModule foo_module modules/mod_foo.so
65 | #
66 | LoadModule mpm_event_module modules/mod_mpm_event.so
67 | #LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
68 | #LoadModule mpm_worker_module modules/mod_mpm_worker.so
69 | LoadModule authn_file_module modules/mod_authn_file.so
70 | #LoadModule authn_dbm_module modules/mod_authn_dbm.so
71 | #LoadModule authn_anon_module modules/mod_authn_anon.so
72 | #LoadModule authn_dbd_module modules/mod_authn_dbd.so
73 | #LoadModule authn_socache_module modules/mod_authn_socache.so
74 | LoadModule authn_core_module modules/mod_authn_core.so
75 | LoadModule authz_host_module modules/mod_authz_host.so
76 | LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
77 | LoadModule authz_user_module modules/mod_authz_user.so
78 | #LoadModule authz_dbm_module modules/mod_authz_dbm.so
79 | #LoadModule authz_owner_module modules/mod_authz_owner.so
80 | #LoadModule authz_dbd_module modules/mod_authz_dbd.so
81 | LoadModule authz_core_module modules/mod_authz_core.so
82 | #LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
83 | #LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
84 | LoadModule access_compat_module modules/mod_access_compat.so
85 | LoadModule auth_basic_module modules/mod_auth_basic.so
86 | #LoadModule auth_form_module modules/mod_auth_form.so
87 | #LoadModule auth_digest_module modules/mod_auth_digest.so
88 | #LoadModule allowmethods_module modules/mod_allowmethods.so
89 | #LoadModule isapi_module modules/mod_isapi.so
90 | #LoadModule file_cache_module modules/mod_file_cache.so
91 | #LoadModule cache_module modules/mod_cache.so
92 | #LoadModule cache_disk_module modules/mod_cache_disk.so
93 | #LoadModule cache_socache_module modules/mod_cache_socache.so
94 | LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
95 | #LoadModule socache_dbm_module modules/mod_socache_dbm.so
96 | #LoadModule socache_memcache_module modules/mod_socache_memcache.so
97 | #LoadModule socache_redis_module modules/mod_socache_redis.so
98 | #LoadModule watchdog_module modules/mod_watchdog.so
99 | #LoadModule macro_module modules/mod_macro.so
100 | #LoadModule dbd_module modules/mod_dbd.so
101 | #LoadModule bucketeer_module modules/mod_bucketeer.so
102 | #LoadModule dumpio_module modules/mod_dumpio.so
103 | #LoadModule echo_module modules/mod_echo.so
104 | #LoadModule example_hooks_module modules/mod_example_hooks.so
105 | #LoadModule case_filter_module modules/mod_case_filter.so
106 | #LoadModule case_filter_in_module modules/mod_case_filter_in.so
107 | #LoadModule example_ipc_module modules/mod_example_ipc.so
108 | #LoadModule buffer_module modules/mod_buffer.so
109 | #LoadModule data_module modules/mod_data.so
110 | #LoadModule ratelimit_module modules/mod_ratelimit.so
111 | LoadModule reqtimeout_module modules/mod_reqtimeout.so
112 | #LoadModule ext_filter_module modules/mod_ext_filter.so
113 | #LoadModule request_module modules/mod_request.so
114 | #LoadModule include_module modules/mod_include.so
115 | LoadModule filter_module modules/mod_filter.so
116 | #LoadModule reflector_module modules/mod_reflector.so
117 | #LoadModule substitute_module modules/mod_substitute.so
118 | #LoadModule sed_module modules/mod_sed.so
119 | #LoadModule charset_lite_module modules/mod_charset_lite.so
120 | #LoadModule deflate_module modules/mod_deflate.so
121 | #LoadModule xml2enc_module modules/mod_xml2enc.so
122 | #LoadModule proxy_html_module modules/mod_proxy_html.so
123 | #LoadModule brotli_module modules/mod_brotli.so
124 | LoadModule mime_module modules/mod_mime.so
125 | #LoadModule ldap_module modules/mod_ldap.so
126 | LoadModule log_config_module modules/mod_log_config.so
127 | #LoadModule log_debug_module modules/mod_log_debug.so
128 | #LoadModule log_forensic_module modules/mod_log_forensic.so
129 | #LoadModule logio_module modules/mod_logio.so
130 | #LoadModule lua_module modules/mod_lua.so
131 | LoadModule env_module modules/mod_env.so
132 | #LoadModule mime_magic_module modules/mod_mime_magic.so
133 | #LoadModule cern_meta_module modules/mod_cern_meta.so
134 | #LoadModule expires_module modules/mod_expires.so
135 | LoadModule headers_module modules/mod_headers.so
136 | #LoadModule ident_module modules/mod_ident.so
137 | #LoadModule usertrack_module modules/mod_usertrack.so
138 | #LoadModule unique_id_module modules/mod_unique_id.so
139 | LoadModule setenvif_module modules/mod_setenvif.so
140 | LoadModule version_module modules/mod_version.so
141 | #LoadModule remoteip_module modules/mod_remoteip.so
142 | #LoadModule proxy_module modules/mod_proxy.so
143 | #LoadModule proxy_connect_module modules/mod_proxy_connect.so
144 | #LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
145 | #LoadModule proxy_http_module modules/mod_proxy_http.so
146 | #LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
147 | #LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
148 | #LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
149 | #LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
150 | #LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
151 | #LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
152 | #LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
153 | #LoadModule proxy_express_module modules/mod_proxy_express.so
154 | #LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
155 | #LoadModule session_module modules/mod_session.so
156 | #LoadModule session_cookie_module modules/mod_session_cookie.so
157 | #LoadModule session_crypto_module modules/mod_session_crypto.so
158 | #LoadModule session_dbd_module modules/mod_session_dbd.so
159 | #LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
160 | #LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
161 | LoadModule ssl_module modules/mod_ssl.so
162 | #LoadModule optional_hook_export_module modules/mod_optional_hook_export.so
163 | #LoadModule optional_hook_import_module modules/mod_optional_hook_import.so
164 | #LoadModule optional_fn_import_module modules/mod_optional_fn_import.so
165 | #LoadModule optional_fn_export_module modules/mod_optional_fn_export.so
166 | #LoadModule dialup_module modules/mod_dialup.so
167 | #LoadModule http2_module modules/mod_http2.so
168 | #LoadModule proxy_http2_module modules/mod_proxy_http2.so
169 | #LoadModule md_module modules/mod_md.so
170 | #LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
171 | #LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
172 | #LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
173 | #LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
174 | LoadModule unixd_module modules/mod_unixd.so
175 | #LoadModule heartbeat_module modules/mod_heartbeat.so
176 | #LoadModule heartmonitor_module modules/mod_heartmonitor.so
177 | #LoadModule dav_module modules/mod_dav.so
178 | LoadModule status_module modules/mod_status.so
179 | LoadModule autoindex_module modules/mod_autoindex.so
180 | #LoadModule asis_module modules/mod_asis.so
181 | #LoadModule info_module modules/mod_info.so
182 | #LoadModule suexec_module modules/mod_suexec.so
183 |
184 | #LoadModule cgid_module modules/mod_cgid.so
185 |
186 |
187 | #LoadModule cgi_module modules/mod_cgi.so
188 |
189 | #LoadModule dav_fs_module modules/mod_dav_fs.so
190 | #LoadModule dav_lock_module modules/mod_dav_lock.so
191 | #LoadModule vhost_alias_module modules/mod_vhost_alias.so
192 | #LoadModule negotiation_module modules/mod_negotiation.so
193 | LoadModule dir_module modules/mod_dir.so
194 | #LoadModule imagemap_module modules/mod_imagemap.so
195 | #LoadModule actions_module modules/mod_actions.so
196 | #LoadModule speling_module modules/mod_speling.so
197 | #LoadModule userdir_module modules/mod_userdir.so
198 | LoadModule alias_module modules/mod_alias.so
199 | #LoadModule rewrite_module modules/mod_rewrite.so
200 |
201 |
202 | #
203 | # If you wish httpd to run as a different user or group, you must run
204 | # httpd as root initially and it will switch.
205 | #
206 | # User/Group: The name (or #number) of the user/group to run httpd as.
207 | # It is usually good practice to create a dedicated user and group for
208 | # running httpd, as with most system services.
209 | #
210 | User daemon
211 | Group daemon
212 |
213 |
214 |
215 | # 'Main' server configuration
216 | #
217 | # The directives in this section set up the values used by the 'main'
218 | # server, which responds to any requests that aren't handled by a
219 | # definition. These values also provide defaults for
220 | # any containers you may define later in the file.
221 | #
222 | # All of these directives may appear inside containers,
223 | # in which case these default settings will be overridden for the
224 | # virtual host being defined.
225 | #
226 |
227 | #
228 | # ServerAdmin: Your address, where problems with the server should be
229 | # e-mailed. This address appears on some server-generated pages, such
230 | # as error documents. e.g. admin@your-domain.com
231 | #
232 | ServerAdmin you@example.com
233 |
234 | #
235 | # ServerName gives the name and port that the server uses to identify itself.
236 | # This can often be determined automatically, but we recommend you specify
237 | # it explicitly to prevent problems during startup.
238 | #
239 | # If your host doesn't have a registered DNS name, enter its IP address here.
240 | #
241 | #ServerName www.example.com:80
242 |
243 | #
244 | # Deny access to the entirety of your server's filesystem. You must
245 | # explicitly permit access to web content directories in other
246 | # blocks below.
247 | #
248 |
249 | AllowOverride none
250 | Require all denied
251 |
252 |
253 | #
254 | # Note that from this point forward you must specifically allow
255 | # particular features to be enabled - so if something's not working as
256 | # you might expect, make sure that you have specifically enabled it
257 | # below.
258 | #
259 |
260 | #
261 | # DocumentRoot: The directory out of which you will serve your
262 | # documents. By default, all requests are taken from this directory, but
263 | # symbolic links and aliases may be used to point to other locations.
264 | #
265 | DocumentRoot "/app/public"
266 |
267 | #
268 | # Possible values for the Options directive are "None", "All",
269 | # or any combination of:
270 | # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
271 | #
272 | # Note that "MultiViews" must be named *explicitly* --- "Options All"
273 | # doesn't give it to you.
274 | #
275 | # The Options directive is both complicated and important. Please see
276 | # http://httpd.apache.org/docs/2.4/mod/core.html#options
277 | # for more information.
278 | #
279 | Options Indexes FollowSymLinks
280 |
281 | #
282 | # AllowOverride controls what directives may be placed in .htaccess files.
283 | # It can be "All", "None", or any combination of the keywords:
284 | # AllowOverride FileInfo AuthConfig Limit
285 | #
286 | AllowOverride None
287 |
288 | #
289 | # Controls who can get stuff from this server.
290 | #
291 | Require all granted
292 |
293 |
294 | #
295 | # DirectoryIndex: sets the file that Apache will serve if a directory
296 | # is requested.
297 | #
298 |
299 | DirectoryIndex index.php
300 |
301 |
302 | #
303 | # The following lines prevent .htaccess and .htpasswd files from being
304 | # viewed by Web clients.
305 | #
306 |
307 | Require all denied
308 |
309 |
310 | #
311 | # ErrorLog: The location of the error log file.
312 | # If you do not specify an ErrorLog directive within a
313 | # container, error messages relating to that virtual host will be
314 | # logged here. If you *do* define an error logfile for a
315 | # container, that host's errors will be logged there and not here.
316 | #
317 | ErrorLog /proc/self/fd/2
318 |
319 | #
320 | # LogLevel: Control the number of messages logged to the error_log.
321 | # Possible values include: debug, info, notice, warn, error, crit,
322 | # alert, emerg.
323 | #
324 | LogLevel warn
325 |
326 |
327 | #
328 | # The following directives define some format nicknames for use with
329 | # a CustomLog directive (see below).
330 | #
331 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
332 | LogFormat "%h %l %u %t \"%r\" %>s %b" common
333 |
334 |
335 | # You need to enable mod_logio.c to use %I and %O
336 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
337 |
338 |
339 | #
340 | # The location and format of the access logfile (Common Logfile Format).
341 | # If you do not define any access logfiles within a
342 | # container, they will be logged here. Contrariwise, if you *do*
343 | # define per- access logfiles, transactions will be
344 | # logged therein and *not* in this file.
345 | #
346 | CustomLog /proc/self/fd/1 common
347 |
348 | #
349 | # If you prefer a logfile with access, agent, and referer information
350 | # (Combined Logfile Format) you can use the following directive.
351 | #
352 | #CustomLog "logs/access_log" combined
353 |
354 |
355 |
356 | #
357 | # Redirect: Allows you to tell clients about documents that used to
358 | # exist in your server's namespace, but do not anymore. The client
359 | # will make a new request for the document at its new location.
360 | # Example:
361 | # Redirect permanent /foo http://www.example.com/bar
362 |
363 | #
364 | # Alias: Maps web paths into filesystem paths and is used to
365 | # access content that does not live under the DocumentRoot.
366 | # Example:
367 | # Alias /webpath /full/filesystem/path
368 | #
369 | # If you include a trailing / on /webpath then the server will
370 | # require it to be present in the URL. You will also likely
371 | # need to provide a section to allow access to
372 | # the filesystem path.
373 |
374 | #
375 | # ScriptAlias: This controls which directories contain server scripts.
376 | # ScriptAliases are essentially the same as Aliases, except that
377 | # documents in the target directory are treated as applications and
378 | # run by the server when requested rather than as documents sent to the
379 | # client. The same rules about trailing "/" apply to ScriptAlias
380 | # directives as to Alias.
381 | #
382 | ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
383 |
384 |
385 |
386 |
387 | #
388 | # ScriptSock: On threaded servers, designate the path to the UNIX
389 | # socket used to communicate with the CGI daemon of mod_cgid.
390 | #
391 | #Scriptsock cgisock
392 |
393 |
394 | #
395 | # "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased
396 | # CGI directory exists, if you have that configured.
397 | #
398 |
399 | AllowOverride None
400 | Options None
401 | Require all granted
402 |
403 |
404 |
405 | #
406 | # Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
407 | # backend servers which have lingering "httpoxy" defects.
408 | # 'Proxy' request header is undefined by the IETF, not listed by IANA
409 | #
410 | RequestHeader unset Proxy early
411 |
412 |
413 |
414 | #
415 | # TypesConfig points to the file containing the list of mappings from
416 | # filename extension to MIME-type.
417 | #
418 | TypesConfig conf/mime.types
419 |
420 | #
421 | # AddType allows you to add to or override the MIME configuration
422 | # file specified in TypesConfig for specific file types.
423 | #
424 | #AddType application/x-gzip .tgz
425 | #
426 | # AddEncoding allows you to have certain browsers uncompress
427 | # information on the fly. Note: Not all browsers support this.
428 | #
429 | #AddEncoding x-compress .Z
430 | #AddEncoding x-gzip .gz .tgz
431 | #
432 | # If the AddEncoding directives above are commented-out, then you
433 | # probably should define those extensions to indicate media types:
434 | #
435 | AddType application/x-compress .Z
436 | AddType application/x-gzip .gz .tgz
437 |
438 | #
439 | # AddHandler allows you to map certain file extensions to "handlers":
440 | # actions unrelated to filetype. These can be either built into the server
441 | # or added with the Action directive (see below)
442 | #
443 | # To use CGI scripts outside of ScriptAliased directories:
444 | # (You will also need to add "ExecCGI" to the "Options" directive.)
445 | #
446 | #AddHandler cgi-script .cgi
447 |
448 | # For type maps (negotiated resources):
449 | #AddHandler type-map var
450 |
451 | #
452 | # Filters allow you to process content before it is sent to the client.
453 | #
454 | # To parse .shtml files for server-side includes (SSI):
455 | # (You will also need to add "Includes" to the "Options" directive.)
456 | #
457 | #AddType text/html .shtml
458 | #AddOutputFilter INCLUDES .shtml
459 |
460 |
461 | #
462 | # The mod_mime_magic module allows the server to use various hints from the
463 | # contents of the file itself to determine its type. The MIMEMagicFile
464 | # directive tells the module where the hint definitions are located.
465 | #
466 | #MIMEMagicFile conf/magic
467 |
468 | #
469 | # Customizable error responses come in three flavors:
470 | # 1) plain text 2) local redirects 3) external redirects
471 | #
472 | # Some examples:
473 | #ErrorDocument 500 "The server made a boo boo."
474 | #ErrorDocument 404 /missing.html
475 | #ErrorDocument 404 "/cgi-bin/missing_handler.pl"
476 | #ErrorDocument 402 http://www.example.com/subscription_info.html
477 | #
478 |
479 | #
480 | # MaxRanges: Maximum number of Ranges in a request before
481 | # returning the entire resource, or one of the special
482 | # values 'default', 'none' or 'unlimited'.
483 | # Default setting is to accept 200 Ranges.
484 | #MaxRanges unlimited
485 |
486 | #
487 | # EnableMMAP and EnableSendfile: On systems that support it,
488 | # memory-mapping or the sendfile syscall may be used to deliver
489 | # files. This usually improves server performance, but must
490 | # be turned off when serving from networked-mounted
491 | # filesystems or if support for these functions is otherwise
492 | # broken on your system.
493 | # Defaults: EnableMMAP On, EnableSendfile Off
494 | #
495 | #EnableMMAP off
496 | #EnableSendfile on
497 |
498 | # Supplemental configuration
499 | #
500 | # The configuration files in the conf/extra/ directory can be
501 | # included to add extra features or to modify the default configuration of
502 | # the server, or you may simply copy their contents here and change as
503 | # necessary.
504 |
505 | # Server-pool management (MPM specific)
506 | #Include conf/extra/httpd-mpm.conf
507 |
508 | # Multi-language error messages
509 | #Include conf/extra/httpd-multilang-errordoc.conf
510 |
511 | # Fancy directory listings
512 | #Include conf/extra/httpd-autoindex.conf
513 |
514 | # Language settings
515 | #Include conf/extra/httpd-languages.conf
516 |
517 | # User home directories
518 | #Include conf/extra/httpd-userdir.conf
519 |
520 | # Real-time info on requests and configuration
521 | #Include conf/extra/httpd-info.conf
522 |
523 | # Virtual hosts
524 | #Include conf/extra/httpd-vhosts.conf
525 |
526 | # Local access to the Apache HTTP Server Manual
527 | #Include conf/extra/httpd-manual.conf
528 |
529 | # Distributed authoring and versioning (WebDAV)
530 | #Include conf/extra/httpd-dav.conf
531 |
532 | # Various default settings
533 | #Include conf/extra/httpd-default.conf
534 |
535 | # Configure mod_proxy_html to understand HTML4/XHTML1
536 |
537 | Include conf/extra/proxy-html.conf
538 |
539 |
540 | # Secure (SSL/TLS) connections
541 | Include conf/extra/httpd-ssl.conf
542 | #
543 | # Note: The following must must be present to support
544 | # starting without SSL on platforms with no /dev/random equivalent
545 | # but a statically compiled-in mod_ssl.
546 | #
547 |
548 | SSLRandomSeed startup builtin
549 | SSLRandomSeed connect builtin
550 |
551 |
552 |
--------------------------------------------------------------------------------
/src/Images/stubs/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 | root /app/public;
5 |
6 | add_header X-Frame-Options "SAMEORIGIN";
7 | add_header X-XSS-Protection "1; mode=block";
8 | add_header X-Content-Type-Options "nosniff";
9 |
10 | index index.php;
11 |
12 | charset utf-8;
13 |
14 | location / {
15 | try_files $uri $uri/ /index.php?$query_string;
16 | }
17 |
18 | location = /favicon.ico { access_log off; log_not_found off; }
19 | location = /robots.txt { access_log off; log_not_found off; }
20 |
21 | error_page 404 /index.php;
22 |
23 | location ~ \.php$ {
24 | #fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
25 | fastcgi_param HTTP_PROXY "";
26 | fastcgi_index index.php;
27 | fastcgi_pass served_php:9000;
28 | #fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
29 | include fastcgi_params;
30 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
31 | fastcgi_buffers 16 16k;
32 | fastcgi_buffer_size 32k;
33 | }
34 |
35 | location ~ /\.(?!well-known).* {
36 | deny all;
37 | }
38 | }
39 |
40 | server {
41 | listen 443 ssl;
42 | server_name localhost;
43 | root /app/public;
44 |
45 | add_header X-Frame-Options "SAMEORIGIN";
46 | add_header X-XSS-Protection "1; mode=block";
47 | add_header X-Content-Type-Options "nosniff";
48 |
49 | ssl_certificate /etc/nginx/ssl/server.crt;
50 | ssl_certificate_key /etc/nginx/ssl/server.key;
51 |
52 | index index.php;
53 |
54 | charset utf-8;
55 |
56 | location / {
57 | try_files $uri $uri/ /index.php?$query_string;
58 | }
59 |
60 | location = /favicon.ico { access_log off; log_not_found off; }
61 | location = /robots.txt { access_log off; log_not_found off; }
62 |
63 | error_page 404 /index.php;
64 |
65 | location ~ \.php$ {
66 | #fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
67 | fastcgi_param HTTP_PROXY "";
68 | fastcgi_index index.php;
69 | fastcgi_pass served_php:9000;
70 | #fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
71 | include fastcgi_params;
72 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
73 | fastcgi_buffers 16 16k;
74 | fastcgi_buffer_size 32k;
75 | }
76 |
77 | location ~ /\.(?!well-known).* {
78 | deny all;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/ServedName.php:
--------------------------------------------------------------------------------
1 | testAllowedCharacters($configName)) {
17 | throw new InvalidNamingException($configName . ' is not a valid name!');
18 | }
19 |
20 | return $configName;
21 | }
22 |
23 | return Str::slug($this->getProjectFolderName(), '_');
24 | }
25 |
26 | protected function testAllowedCharacters($name)
27 | {
28 | preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_.-]+/', $name, $matches);
29 |
30 | return $matches && $matches[0] === $name;
31 | }
32 |
33 | public function getProjectFolderName(): string
34 | {
35 | return basename(base_path());
36 | }
37 | }
--------------------------------------------------------------------------------
/src/ServedServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(
25 | __DIR__ . '/config/served.php', 'served'
26 | );
27 | }
28 |
29 | /**
30 | * Bootstrap services.
31 | *
32 | * @return void
33 | */
34 | public function boot()
35 | {
36 | $this->publishes([
37 | __DIR__ . '/config/served.php' => config_path('served.php')
38 | ], 'served-config');
39 |
40 | if ($this->app->runningInConsole()) {
41 | $this->commands([
42 | ServedUpCommand::class,
43 | ServedRunCommand::class,
44 | ServedStartCommand::class,
45 | ServedStopCommand::class,
46 | ServedTearDownCommand::class,
47 | ServedListCommand::class,
48 | ServedSshCommand::class,
49 | ServedXdebugCommand::class,
50 | ]);
51 | }
52 |
53 | $this->app->singleton('served.name', function () {
54 | return (new ServedName())->projectName();
55 | });
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/ServiceManager.php:
--------------------------------------------------------------------------------
1 | php();
37 |
38 | $web = $this->web();
39 |
40 | $baseServices = collect([$php, $web]);
41 |
42 | foreach (config('served.extras', []) as $name => $config) {
43 | $extras[] = $this->resolve($name, Arr::get($config, 'service'), $config);
44 | }
45 |
46 | return $baseServices->merge($extras);
47 | }
48 |
49 | /**
50 | * ServiceManager constructor.
51 | * @param Shell $shell
52 | */
53 | public function __construct(Shell $shell)
54 | {
55 | $this->shell = $shell;
56 | }
57 |
58 | /**
59 | * @param string $service
60 | * @param $callback
61 | */
62 | public function extend(string $service, $callback)
63 | {
64 | $this->extendables[$service] = $callback;
65 | }
66 |
67 | /**
68 | * @return mixed|ApacheService|MysqlService|NginxService|PhpService
69 | * @throws Exception
70 | */
71 | public function php()
72 | {
73 | $config = config('served.php');
74 | return $this->resolve('php', Arr::get($config, 'service', 'php'), $config);
75 | }
76 |
77 | /**
78 | * @return mixed|ApacheService|MysqlService|NginxService|PhpService
79 | * @throws Exception
80 | */
81 | public function web()
82 | {
83 | $config = config('served.web');
84 | return $this->resolve('web', Arr::get($config, 'service', 'nginx'), $config);
85 | }
86 |
87 | /**
88 | * @param string $name
89 | * @param string $service
90 | * @param array $config
91 | * @return mixed|ApacheService|MysqlService|NginxService|PhpService
92 | * @throws Exception
93 | */
94 | public function resolve(string $name, string $service, array $config)
95 | {
96 | if (isset($this->extendables[$name])) {
97 | return call_user_func($this->extendables, $name, $config, $this->shell);
98 | }
99 |
100 | switch ($service) {
101 | case 'php':
102 | return new PhpService($name, $config, $this->shell);
103 |
104 | case 'apache':
105 | case 'apache2':
106 | return new ApacheService($name, $config, $this->shell);
107 |
108 | case 'nginx':
109 | return new NginxService($name, $config, $this->shell);
110 |
111 | case 'mysql':
112 | return new MysqlService($name, $config, $this->shell);
113 |
114 | case 'postgres':
115 | case 'pgsql':
116 | return new PostgresService($name, $config, $this->shell);
117 |
118 | case 'redis':
119 | return new RedisService($name, $config, $this->shell);
120 |
121 | case 'memcached':
122 | return new MemcachedService($name, $config, $this->shell);
123 |
124 | case 'mailhog':
125 | return new MailhogService($name, $config, $this->shell);
126 |
127 | case null:
128 | throw new Exception('No service specified for ' . $name);
129 |
130 | default:
131 | throw new Exception('Service ', $service . ' wasn\'t found for ' . $name);
132 |
133 | }
134 | }
135 |
136 | /**
137 | * @param string $name
138 | * @return mixed|ApacheService|MysqlService|NginxService|PhpService
139 | * @throws Exception
140 | */
141 | public function resolveByName(string $name)
142 | {
143 | if ($name === 'php') {
144 | return $this->php();
145 | }
146 |
147 | if ($name === 'web') {
148 | return $this->web();
149 | }
150 | if ($config = config('served.extras.' . $name)) {
151 | return $this->resolve($name, Arr::get($config, 'service'), $config);
152 | }
153 |
154 | throw new Exception('Could not resolve ' . $name);
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/Services/ApacheService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new ApacheImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/MailhogService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new MailhogImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/MemcachedService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new MemcachedImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/MysqlService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new MysqlImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/NginxService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new NginxImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/PhpService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new PhpImage($this->name, $this->config, $this->shell);
31 | }
32 |
33 | public function enableXdebug(): void
34 | {
35 | $this->container()->enableXdebug();
36 | }
37 |
38 | public function disableXdebug(): void
39 | {
40 | $this->container()->disableXdebug();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Services/PostgresService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new PostgresImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/RedisService.php:
--------------------------------------------------------------------------------
1 | name, $this->config, $this->shell);
23 | }
24 |
25 | /**
26 | * @inheritDoc
27 | */
28 | public function image(): Image
29 | {
30 | return new RedisImage($this->name, $this->config, $this->shell);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Services/Service.php:
--------------------------------------------------------------------------------
1 | name = $name;
43 | $this->config = $config;
44 | $this->shell = $shell;
45 | }
46 |
47 | /**
48 | * @param bool $noCache
49 | *
50 | * @return void
51 | */
52 | public function build($noCache = false): void
53 | {
54 | $this->image()->prepareBuild()->build($noCache);
55 | }
56 |
57 | /**
58 | * @return void
59 | */
60 | public function run(): void
61 | {
62 | $this->container()->prepare()->run();
63 | }
64 |
65 | /**
66 | * @return string
67 | */
68 | public function name(): string
69 | {
70 | return $this->name;
71 | }
72 |
73 | /**
74 | * @return string
75 | */
76 | public function serviceName(): string
77 | {
78 | if (isset($this->serviceName)) {
79 | return $this->serviceName;
80 |
81 | }
82 | return class_basename($this);
83 | }
84 |
85 | /**
86 | * @return string
87 | */
88 | public function imageName(): string
89 | {
90 | return sprintf('%s %s', $this->serviceName(), $this->image()->imageTag());
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/Services/ServiceInterface.php:
--------------------------------------------------------------------------------
1 | internal_getDefaultEnv();
13 |
14 | return $this->internal_replacePlaceholders($command, $env);
15 | }
16 |
17 | protected function internal_getDefaultEnv() {
18 | return $this->privateMethod($this, 'getDefaultEnv')->invoke($this);
19 | }
20 |
21 | protected function internal_replacePlaceholders($command, $env = []) {
22 | return $this->privateMethod($this, 'replacePlaceholders')->invoke($this, $command, $env);
23 | }
24 |
25 | private function privateMethod($object, $method) {
26 | $object = new \ReflectionObject($object);
27 | $method = $object->getMethod($method);
28 | $method->setAccessible(true);
29 | return $method;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Shell/Shell.php:
--------------------------------------------------------------------------------
1 | output = $output;
23 | }
24 |
25 | /**
26 | * @param string $command
27 | * @param array $env
28 | */
29 | public function run(string $command, array $env = []): void
30 | {
31 | $process = Process::fromShellCommandline($command);
32 | if ($this->output->isVerbose()) {
33 | $this->writeCommand($process, $command, $env);
34 | }
35 | $process->setTimeout(null);
36 |
37 | $process->run($this->writeOutputBuffer(), $env);
38 | }
39 |
40 | /**
41 | * @param string $command
42 | * @param array $env
43 | * @return string
44 | */
45 | public function exec(string $command, array $env = []): string
46 | {
47 | $process = Process::fromShellCommandline($command);
48 | $process->setTimeout(null);
49 | if ($this->output->isVerbose()) {
50 | $this->writeCommand($process, $command, $env);
51 | }
52 | $callback = null;
53 | if ($this->output->isVeryVerbose()) {
54 | $callback = $this->writeOutputBuffer();
55 | }
56 | $process->run($callback, $env);
57 |
58 | if (!$process->isSuccessful()) {
59 | throw new ProcessFailedException($process);
60 | }
61 |
62 | return $process->getOutput();
63 | }
64 |
65 | protected function writeCommand(Process $process, $command, $env = [])
66 | {
67 | $this->output->writeln($process->createCommand($command, $env));
68 | }
69 |
70 | protected function writeOutputBuffer() {
71 | return function ($type, $buffer) {
72 | if (Process::ERR === $type) {
73 | throw new ShellCommandFailedException('ERROR : : ' . trim($buffer));
74 | // $this->output->writeln('ERROR : ' . $buffer);
75 | } else {
76 | $this->output->writeln($buffer);
77 | }
78 | };
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Traits/Storage.php:
--------------------------------------------------------------------------------
1 | name();
16 | $storagePath = storage_path($basePath);
17 |
18 | if (!is_dir($storagePath)) {
19 | if (!mkdir($storagePath, 0777, true) && !is_dir($storagePath)) {
20 | throw new RuntimeException(sprintf('Directory "%s" was not created', $storagePath));
21 | }
22 | }
23 |
24 | if ($relative) {
25 | $storagePath = 'storage/' . $basePath;
26 | }
27 |
28 | return $storagePath . '/';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/config/served.php:
--------------------------------------------------------------------------------
1 | env('SERVED_NAME'),
14 |
15 | /**
16 | * If you are behind a proxy, you might need to
17 | * specify this to enable docker to gain access
18 | * to the internet while building your images
19 | */
20 | 'proxy' => [
21 | 'http' => env('SERVED_HTTP_PROXY', ''),
22 | 'https' => env('SERVED_HTTPS_PROXY', ''),
23 | ],
24 |
25 | /*
26 | |--------------------------------------------------------------------------
27 | | PHP Server
28 | |--------------------------------------------------------------------------
29 | |
30 | | Here you can setup which php version you wish to run.
31 | | If no version is specified, latest will be used
32 | |
33 | | Under the modules array, you may add any php modules you wish to install.
34 | | A complete list of modules can be found at:
35 | | https://github.com/mlocati/docker-php-extension-installer#supported-php-extensions
36 | |
37 | */
38 | 'php' => [
39 | 'version' => env('SERVED_PHP_VERSION', '7.4'),
40 | 'modules' => [
41 | 'pdo_mysql',
42 | 'zip',
43 | 'bcmath'
44 | ],
45 | 'npm' => true,
46 | 'xdebug' => [
47 | 'enabled' => env('SERVED_XDEBUG_ENABLED', true),
48 | 'port' => 9001,
49 | ],
50 | ],
51 | 'web' => [
52 | 'service' => 'nginx', //or apache
53 | 'version' => '1.9.2', //apache currently only supports latest!
54 | 'port' => env('SERVED_WEB_PORT', 8095),
55 | 'ssl_port' => env('SERVED_WEB_SSL_PORT', 4443),
56 | ],
57 | 'extras' => [
58 | 'mysql' => [
59 | 'service' => 'mysql',
60 | 'version' => '5.7',
61 | 'port' => env('SERVED_EXTERNAL_DB_PORT', 3306),
62 | 'root_password' => 'password',
63 | 'database' => env('DB_DATABASE', 'laravel'),
64 | 'username' => env('DB_USERNAME', 'laravel'),
65 | 'password' => env('DB_PASSWORD', 'password'),
66 | ],
67 | ],
68 | ];
69 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | mock(OutputInterface::class);
15 | }
16 |
17 | protected function getExpectedContent($filename)
18 | {
19 | return file_get_contents(__DIR__ . '/expected/' . $filename);
20 | }
21 |
22 | protected function getPackageProviders($app)
23 | {
24 | return [ServedServiceProvider::class];
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Unit/DockerImageTest.php:
--------------------------------------------------------------------------------
1 | writeDockerFile();
28 |
29 | $this->assertEquals($this->getExpectedContent('DockerFile-apache'), $content);
30 | }
31 |
32 | /** @test */
33 | public function it_can_make_nginx_docker_file()
34 | {
35 | $image = new NginxImage('test', [], app(Shell::class));
36 | $content = $image->writeDockerFile();
37 |
38 | $this->assertEquals($this->getExpectedContent('DockerFile-nginx'), $content);
39 | }
40 |
41 | /** @test */
42 | public function it_can_make_php_docker_file()
43 | {
44 | $image = new PhpImage('test', [], app(Shell::class));
45 | $content = $image->writeDockerFile();
46 |
47 | $this->assertEquals($this->getExpectedContent('DockerFile-php'), $content);
48 | }
49 |
50 | /** @test */
51 | public function it_can_make_mysql_docker_file()
52 | {
53 | $image = new MysqlImage('test', [], app(Shell::class));
54 | $content = $image->writeDockerFile();
55 |
56 | $this->assertEquals($this->getExpectedContent('DockerFile-mysql'), $content);
57 | }
58 |
59 | /** @test */
60 | public function it_can_make_postgres_docker_file()
61 | {
62 | $image = new RedisImage('test', [], app(Shell::class));
63 | $content = $image->writeDockerFile();
64 |
65 | $this->assertEquals($this->getExpectedContent('DockerFile-redis'), $content);
66 | }
67 |
68 | /** @test */
69 | public function it_can_make_redis_docker_file()
70 | {
71 | $image = new RedisImage('test', [], app(Shell::class));
72 | $content = $image->writeDockerFile();
73 |
74 | $this->assertEquals($this->getExpectedContent('DockerFile-redis'), $content);
75 | }
76 |
77 | /** @test */
78 | public function it_can_make_memcached_docker_file()
79 | {
80 | $image = new MemcachedImage('test', [], app(Shell::class));
81 | $content = $image->writeDockerFile();
82 |
83 | $this->assertEquals($this->getExpectedContent('DockerFile-memcached'), $content);
84 | }
85 |
86 | /** @test */
87 | public function it_can_make_mailhog_docker_file()
88 | {
89 | $image = new MailhogImage('test', [], app(Shell::class));
90 | $content = $image->writeDockerFile();
91 |
92 | $this->assertEquals($this->getExpectedContent('DockerFile-mailhog'), $content);
93 | }
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/tests/Unit/DockerRunTest.php:
--------------------------------------------------------------------------------
1 | app->config->set('served.name', 'served');
22 | $this->app->setBasePath('/path');
23 | }
24 |
25 | /** @test */
26 | public function it_gets_correct_apache_run_command()
27 | {
28 | $container = new ApacheContainer('apache_test', [], app(Shell::class));
29 |
30 | $expected = 'docker run -d --restart always --name "${:container_name}" \
31 | --network="${:network}" \
32 | -p="${:port}":80 \
33 | -p="${:ssl_port}":443 \
34 | -v="${:local_dir}":/app "${:image_name}"';
35 |
36 | $this->assertEquals($expected, $container->getDockerRunCommand());
37 |
38 | }
39 |
40 | /** @test */
41 | public function it_gets_correct_apache_env()
42 | {
43 | $container = new ApacheContainer('apache_test', ['port' => 8090, 'ssl_port' => 4443], app(Shell::class));
44 |
45 | $expected = [
46 | 'network' => 'served',
47 | 'container_name' => 'served_served_apache_test',
48 | 'image_name' => 'served/served_apache_test',
49 | 'port' => 8090,
50 | 'ssl_port' => 4443,
51 | 'local_dir' => '/path',
52 |
53 | ];
54 |
55 | $this->assertEquals($expected, $container->getEnv());
56 |
57 | }
58 |
59 | /** @test */
60 | public function it_gets_correct_nginx_run_command()
61 | {
62 | $container = new NginxContainer('nginx_test', [], app(Shell::class));
63 |
64 | $expected = 'docker run -d --restart always --name "${:container_name}" \
65 | --network="${:network}" \
66 | -p="${:port}":80 \
67 | -p="${:ssl_port}":443 \
68 | -v="${:local_dir}":/app "${:image_name}"';
69 |
70 | $this->assertEquals($expected, $container->getDockerRunCommand());
71 |
72 | }
73 |
74 | /** @test */
75 | public function it_gets_correct_nginx_env()
76 | {
77 | $container = new NginxContainer('nginx_test', ['port' => 8090, 'ssl_port' => 443], app(Shell::class));
78 |
79 | $expected = [
80 | 'network' => 'served',
81 | 'container_name' => 'served_served_nginx_test',
82 | 'image_name' => 'served/served_nginx_test',
83 | 'port' => 8090,
84 | 'ssl_port' => 443,
85 | 'local_dir' => '/path',
86 |
87 | ];
88 |
89 | $this->assertEquals($expected, $container->getEnv());
90 |
91 | }
92 |
93 | /** @test */
94 | public function it_gets_correct_php_run_command()
95 | {
96 | $container = new PhpContainer('php_test', ['volumes' => ['/some/local/path:/some/docker/path']], app(Shell::class));
97 |
98 | $expected = 'docker run -d --restart always --name "${:container_name}" \
99 | --user=served:served \
100 | --network="${:network}" \
101 | --network-alias=served_php \
102 | -v="${:local_dir}":/app -v="/some/local/path:/some/docker/path" "${:image_name}"';
103 |
104 | $this->assertEquals($expected, $container->getDockerRunCommand());
105 |
106 | }
107 |
108 | /** @test */
109 | public function it_gets_correct_php_env()
110 | {
111 | $container = new PhpContainer('php_test', [], app(Shell::class));
112 |
113 | $expected = [
114 | 'network' => 'served',
115 | 'container_name' => 'served_served_php_test',
116 | 'image_name' => 'served/served_php_test',
117 | 'local_dir' => '/path',
118 |
119 | ];
120 |
121 | $this->assertEquals($expected, $container->getEnv());
122 |
123 | }
124 |
125 | /** @test */
126 | public function it_gets_correct_mysql_run_command()
127 | {
128 | $container = new MysqlContainer('mysql_test', [], app(Shell::class));
129 |
130 | $expected = 'docker run -d --restart always --name "${:container_name}" \
131 | --network="${:network}" \
132 | --network-alias="${:alias}" \
133 | -p="${:port}":3306 \
134 | -v="${:volume}":/var/lib/mysql/ "${:image_name}"';
135 |
136 | $this->assertEquals($expected, $container->getDockerRunCommand());
137 |
138 | }
139 |
140 | /** @test */
141 | public function it_gets_correct_mysql_env()
142 | {
143 | $container = new MysqlContainer('mysql_test', ['port' => 3212], app(Shell::class));
144 |
145 | $expected = [
146 | 'network' => 'served',
147 | 'container_name' => 'served_served_mysql_test',
148 | 'image_name' => 'served/served_mysql_test',
149 | 'port' => 3212,
150 | 'alias' => 'mysql_test',
151 | 'volume' => 'served_mysql_test',
152 |
153 | ];
154 |
155 | $this->assertEquals($expected, $container->getEnv());
156 |
157 | }
158 |
159 | /** @test */
160 | public function it_gets_correct_postgres_run_command()
161 | {
162 | $container = new PostgresContainer('postgres_test', [], app(Shell::class));
163 |
164 | $expected = 'docker run -d --restart always --name "${:container_name}" \
165 | --network="${:network}" \
166 | --network-alias="${:alias}" \
167 | -p="${:port}":5432 \
168 | -v="${:volume}":/var/lib/postgresql/data "${:image_name}"';
169 |
170 | $this->assertEquals($expected, $container->getDockerRunCommand());
171 |
172 | }
173 |
174 | /** @test */
175 | public function it_gets_correct_postgres_env()
176 | {
177 | $container = new PostgresContainer('postgres_test', ['port' => 3212], app(Shell::class));
178 |
179 | $expected = [
180 | 'network' => 'served',
181 | 'container_name' => 'served_served_postgres_test',
182 | 'image_name' => 'served/served_postgres_test',
183 | 'port' => 3212,
184 | 'alias' => 'postgres_test',
185 | 'volume' => 'served_postgres_test',
186 |
187 | ];
188 |
189 | $this->assertEquals($expected, $container->getEnv());
190 |
191 | }
192 |
193 |
194 | /** @test */
195 | public function it_gets_correct_redis_run_command()
196 | {
197 | $container = new RedisContainer('redis_test', [], app(Shell::class));
198 |
199 | $expected = 'docker run -d --restart always --name "${:container_name}" \
200 | --network="${:network}" \
201 | --network-alias="${:alias}" "${:image_name}"';
202 |
203 | $this->assertEquals($expected, $container->getDockerRunCommand());
204 |
205 | }
206 |
207 | /** @test */
208 | public function it_gets_correct_redis_env()
209 | {
210 | $container = new RedisContainer('redis_test', [], app(Shell::class));
211 |
212 | $expected = [
213 | 'network' => 'served',
214 | 'container_name' => 'served_served_redis_test',
215 | 'image_name' => 'served/served_redis_test',
216 | 'alias' => 'redis_test',
217 |
218 | ];
219 |
220 | $this->assertEquals($expected, $container->getEnv());
221 |
222 | }
223 |
224 | /** @test */
225 | public function it_gets_correct_memcached_run_command()
226 | {
227 | $container = new MemcachedContainer('memcached_test', [], app(Shell::class));
228 |
229 | $expected = 'docker run -d --restart always --name "${:container_name}" \
230 | --network="${:network}" \
231 | --network-alias="${:alias}" "${:image_name}"';
232 |
233 | $this->assertEquals($expected, $container->getDockerRunCommand());
234 |
235 | }
236 |
237 | /** @test */
238 | public function it_gets_correct_memcached_env()
239 | {
240 | $container = new MemcachedContainer('memcached_test', [], app(Shell::class));
241 |
242 | $expected = [
243 | 'network' => 'served',
244 | 'container_name' => 'served_served_memcached_test',
245 | 'image_name' => 'served/served_memcached_test',
246 | 'alias' => 'memcached_test',
247 |
248 | ];
249 |
250 | $this->assertEquals($expected, $container->getEnv());
251 |
252 | }
253 |
254 | /** @test */
255 | public function it_gets_correct_mailhog_run_command()
256 | {
257 | $container = new MailhogContainer('mailhog_test', [], app(Shell::class));
258 |
259 | $expected = 'docker run -d --restart always --name "${:container_name}" \
260 | --network="${:network}" \
261 | --network-alias="${:alias}" \
262 | -p "${:port}":8025 "${:image_name}"';
263 |
264 | $this->assertEquals($expected, $container->getDockerRunCommand());
265 |
266 | }
267 |
268 | /** @test */
269 | public function it_gets_correct_mailhog_env()
270 | {
271 | $container = new RedisContainer('mailhog_test', [], app(Shell::class));
272 |
273 | $expected = [
274 | 'network' => 'served',
275 | 'container_name' => 'served_served_mailhog_test',
276 | 'image_name' => 'served/served_mailhog_test',
277 | 'alias' => 'mailhog_test',
278 |
279 | ];
280 |
281 | $this->assertEquals($expected, $container->getEnv());
282 |
283 | }
284 |
285 | }
286 |
--------------------------------------------------------------------------------
/tests/Unit/NamingTest.php:
--------------------------------------------------------------------------------
1 | app->config->set('served.name', 'my_project');
21 |
22 | $this->assertEquals('my_project', $this->app->get('served.name'));
23 | }
24 |
25 | /** @test */
26 | public function it_fails_on_invalid_name()
27 | {
28 | $this->app->config->set('served.name', 'bad|name');
29 |
30 | $this->expectException(InvalidNamingException::class);
31 |
32 | $this->app->get('served.name');
33 |
34 | }
35 |
36 | /** @test */
37 | public function it_fails_on_invalid_name_with_space()
38 | {
39 | $this->app->config->set('served.name', 'bad name');
40 |
41 | $this->expectException(InvalidNamingException::class);
42 |
43 | $this->app->get('served.name');
44 |
45 | }
46 |
47 | /** @test */
48 | public function it_fails_on_invalid_start_character()
49 | {
50 | $this->app->config->set('served.name', '_badname');
51 |
52 | $this->expectException(InvalidNamingException::class);
53 |
54 | $this->app->get('served.name');
55 |
56 | }
57 |
58 | /** @test */
59 | public function it_fails_on_invalid_random_characters()
60 | {
61 | $this->app->config->set('served.name', '_bad|dsad|_23');
62 |
63 | $this->expectException(InvalidNamingException::class);
64 |
65 | $this->app->get('served.name');
66 |
67 | }
68 |
69 | /** @test */
70 | public function it_can_handle_special_characters()
71 | {
72 | $nameHandler = Mockery::mock(ServedName::class)->makePartial();
73 |
74 | $nameHandler->shouldReceive('getProjectFolderName')
75 | ->andReturn('test-s.123|test');
76 |
77 | $this->assertEquals('test_s123test', $nameHandler->projectName());
78 | }
79 |
80 | /** @test */
81 | public function it_can_handle_whitespace()
82 | {
83 | $nameHandler = Mockery::mock(ServedName::class)->makePartial();
84 |
85 | $nameHandler->shouldReceive('getProjectFolderName')
86 | ->andReturn('test test');
87 |
88 | $this->assertEquals('test_test', $nameHandler->projectName());
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/tests/expected/DockerFile-apache:
--------------------------------------------------------------------------------
1 | FROM webdevops/apache:latest
2 | ENV WEB_PHP_SOCKET=served_php:9000
3 | ENV WEB_DOCUMENT_ROOT=/app/public
4 | ENV WEB_PHP_TIMEOUT=60
5 | COPY storage/app/served/test/localhost.key /opt/docker/etc/httpd/ssl/server.key
6 | COPY storage/app/served/test/localhost.crt /opt/docker/etc/httpd/ssl/server.crt
--------------------------------------------------------------------------------
/tests/expected/DockerFile-mailhog:
--------------------------------------------------------------------------------
1 | FROM mailhog/mailhog:latest
--------------------------------------------------------------------------------
/tests/expected/DockerFile-memcached:
--------------------------------------------------------------------------------
1 | FROM library/memcached:latest
--------------------------------------------------------------------------------
/tests/expected/DockerFile-mysql:
--------------------------------------------------------------------------------
1 | FROM library/mysql:5.7
2 |
3 | # Setting env vars for mysql init
4 | ENV MYSQL_ROOT_PASSWORD=password
5 | ENV MYSQL_DATABASE=laravel
6 | ENV MYSQL_USER=laravel
7 | ENV MYSQL_PASSWORD=password
--------------------------------------------------------------------------------
/tests/expected/DockerFile-nginx:
--------------------------------------------------------------------------------
1 | FROM library/nginx:1.19
2 |
3 | # Copy in new nginx config
4 | COPY storage/app/served/test/default.conf /etc/nginx/conf.d/default.conf
5 | COPY storage/app/served/test/localhost.key /etc/nginx/ssl/server.key
6 | COPY storage/app/served/test/localhost.crt /etc/nginx/ssl/server.crt
--------------------------------------------------------------------------------
/tests/expected/DockerFile-php:
--------------------------------------------------------------------------------
1 | FROM library/php:7.4-fpm
2 |
3 | # disable warnings for "dangerous" messages
4 | ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1
5 |
6 | # Adding linux packages
7 | RUN apt-get update \
8 | && apt-get install -y unzip zip gnupg \
9 | && rm -rf /var/lib/apt/lists/*
10 | # Installing packages for sql dump
11 | RUN set -ex; \
12 | key='8C718D3B5072E1F5'; \
13 | export GNUPGHOME="$(mktemp -d)"; \
14 | gpg --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key"; \
15 | gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
16 | gpgconf --kill all; \
17 | rm -rf "$GNUPGHOME"; \
18 | apt-key list > /dev/null
19 |
20 | RUN echo "deb http://repo.mysql.com/apt/debian/ buster mysql-8.0" > /etc/apt/sources.list.d/mysql.list \
21 | && apt-get update \
22 | && apt-get install -y mysql-community-client postgresql-client sqlite3 \
23 | && rm -rf /var/lib/apt/lists/*
24 |
25 | # add development php.ini file
26 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
27 | # add a local user with the same uid as the local
28 | # prepare empty composer config directory
29 | # ensure user owns its home directory
30 | ARG uid
31 | RUN useradd -G root -u $uid -d /home/served served \
32 | && mkdir -p /home/served/.composer \
33 | && chown -R served:served /home/served
34 |
35 | # add composer
36 | # set composer to use https
37 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer \
38 | && runuser -l served -c "composer config --global repos.packagist composer https://packagist.org"
39 |
40 | # Set work dir
41 | WORKDIR /app
--------------------------------------------------------------------------------
/tests/expected/DockerFile-postgres:
--------------------------------------------------------------------------------
1 | FROM library/postgres:12.4
2 |
3 | # Setting env vars for postgres init
4 | ENV POSTGRES_DB=laravel
5 | ENV POSTGRES_USER=laravel
6 | ENV POSTGRES_PASSWORD=password
--------------------------------------------------------------------------------
/tests/expected/DockerFile-redis:
--------------------------------------------------------------------------------
1 | FROM library/redis:latest
2 | CMD [ "redis-server" ]
--------------------------------------------------------------------------------