├── .gitattributes
├── .github
└── FUNDING.yml
├── .gitignore
├── README.md
├── backups
└── .gitignore
├── certbot
├── .certbot.lock
└── ssl-dhparam.pem
├── database
├── conf.d
│ └── z-mysql.cnf
└── phpmyadmin
│ └── sql
│ └── create_tables.sql.template.example
├── docker-compose.yml
├── env.example
├── install.sh
├── php-fpm
├── php-fpm.d
│ └── z-www.conf
└── php
│ └── conf.d
│ └── security.ini
├── phpmyadmin
├── apache2
│ ├── ports.conf
│ └── sites-available
│ │ ├── 000-default.conf
│ │ └── default-ssl.sample.conf
├── config.user.inc.php
├── php
│ └── conf.d
│ │ └── security.ini
└── ssl-option
│ └── options-ssl-apache.conf
├── portainer-docker-compose.yml
├── redis
└── redis.conf
├── ssl-conf.sh
├── varnish
└── default.vcl
├── webserver
├── nginx.conf
├── ssl-option
│ └── options-ssl-nginx.conf
└── templates
│ └── nginx.conf.template
└── wordpress
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [damalis]
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [full stack nginx WordPress for everyone with docker compose](https://github.com/damalis/full-stack-nginx-wordpress-for-everyone-with-docker-compose)
2 |
3 | If You want to build a website with WordPress at short time;
4 |
5 | #### Full stack Nginx WordPress:
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Plus, manage docker containers with Portainer.
22 |
23 | #### Supported CPU architectures:
24 | arm64/aarch64, x86-64
25 |
26 | #### Supported Linux Package Manage Systems:
27 | apk, dnf, yum, apt/apt-get, zypper, pacman
28 |
29 | #### Supported Linux Operation Systems:
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | ##### Note: Fedora 37, 39 and alpine linux x86-64 compatible, could not try sles IBM Z s390x, rhel IBM Z s390x and raspberrypi.
41 |
42 | #### With this project you can quickly run the following:
43 |
44 | - [WordPress (php-fpm)](https://hub.docker.com/_/wordpress)
45 | - [webserver (nginx)](https://hub.docker.com/_/nginx)
46 | - [certbot (letsencrypt)](https://hub.docker.com/r/certbot/certbot)
47 | - [phpMyAdmin](https://hub.docker.com/r/phpmyadmin/phpmyadmin/)
48 | - [databaseMariadb](https://hub.docker.com/_/mariadb) [databaseMysql](https://hub.docker.com/_/mysql)
49 | - [redis](https://hub.docker.com/_/redis)
50 | - [varnish](https://hub.docker.com/_/varnish)
51 | - [backup](https://hub.docker.com/r/offen/docker-volume-backup)
52 |
53 | #### For certbot (letsencrypt) certificate:
54 |
55 | - [Set DNS configuration of your domain name](https://support.google.com/a/answer/48090?hl=en)
56 |
57 | #### IPv4/IPv6 Firewall
58 | Create rules to open ports to the internet, or to a specific IPv4 address or range.
59 |
60 | - http: 80
61 | - https: 443
62 | - portainer: 9001
63 | - phpmyadmin: 9090
64 |
65 | #### Note
66 |
67 | To optimize upload images, look at [the damalis repository](https://github.com/damalis/full-stack-nodejs-image-optimizer-for-everyone-with-damalis-repository)
68 |
69 | #### Required Ram
70 |
71 | require up to 2 GB of RAM for **Docker** and **Docker Compose**.
72 |
73 | #### Contents:
74 |
75 | - [Auto Configuration and Installation](#automatic)
76 | - [Requirements](#requirements)
77 | - [Manual Configuration and Installation](#manual)
78 | - [Portainer Installation](#portainer)
79 | - [Usage](#usage)
80 | - [Website](#website)
81 | - [Webserver](#webserver)
82 | - [Redis Plugin](#redis-plugin)
83 | - [Varnish Plugin](#varnish-plugin)
84 | - [phpMyAdmin](#phpmyadmin)
85 | - [backup](#backup)
86 |
87 | ## Automatic
88 |
89 | ### Exec install shell script for auto installation and configuration
90 |
91 | download with
92 |
93 | ```
94 | git clone https://github.com/damalis/full-stack-nginx-wordpress-for-everyone-with-docker-compose.git
95 | ```
96 |
97 | Open a terminal and `cd` to the folder in which `docker-compose.yml` is saved and run:
98 |
99 | ```
100 | cd full-stack-nginx-wordpress-for-everyone-with-docker-compose
101 | chmod +x install.sh
102 | ./install.sh
103 | ```
104 |
105 | ## Requirements
106 |
107 | Make sure you have the latest versions of **Docker** and **Docker Compose** installed on your machine and require up to 2 GB of RAM.
108 |
109 | - [How install docker](https://docs.docker.com/engine/install/)
110 | - [How install docker compose](https://docs.docker.com/compose/install/)
111 |
112 | Clone this repository or copy the files from this repository into a new folder.
113 |
114 | Make sure to [add your user to the `docker` group](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user).
115 |
116 | ## Manual
117 |
118 | ### Configuration
119 |
120 | download with
121 |
122 | ```
123 | git clone https://github.com/damalis/full-stack-nginx-wordpress-for-everyone-with-docker-compose.git
124 | ```
125 |
126 | Open a terminal and `cd` to the folder in which `docker-compose.yml` is saved and run:
127 |
128 | ```
129 | cd full-stack-nginx-wordpress-for-everyone-with-docker-compose
130 | ```
131 |
132 | Copy the example environment into `.env`
133 |
134 | ```
135 | cp env.example .env
136 | ```
137 |
138 | Edit the `.env` file to change values of ```LOCAL_TIMEZONE```, ```DOMAIN_NAME```, ```DIRECTORY_PATH```, ```LETSENCRYPT_EMAIL```, ```WORDPRESS_DB_USER```, ```WORDPRESS_DB_PASSWORD```, ```WORDPRESS_DB_NAME```, ```WORDPRESS_TABLE_PREFIX```, ```MYSQL_ROOT_PASSWORD```, ```DATABASE_IMAGE_NAME```, ```DATABASE_CONT_NAME```, ```DATABASE_PACKAGE_MANAGER```, ```DATABASE_ADMIN_COMMANDLINE```, ```PMA_CONTROLUSER```, ```PMA_CONTROLPASS```, ```PMA_HTPASSWD_USERNAME```, ```PMA_HTPASSWD_PASSWORD``` and ```VARNISH_VERSION```.
139 |
140 | LOCAL_TIMEZONE=[to see local timezones](https://docs.diladele.com/docker/timezones.html)
141 |
142 | DIRECTORY_PATH=```pwd``` at command line\
143 | DATABASE_IMAGE_NAME=```mariadb``` or ```mysql```\
144 | DATABASE_CONT_NAME=```mariadb```, ```mysql``` or ```custom name```\
145 | DATABASE_PACKAGE_MANAGER=```apt-get update && apt-get install -y gettext-base``` for mariadb, ```microdnf install -y gettext``` for mysql\
146 | DATABASE_ADMIN_COMMANDLINE=```mariadb-admin``` for mariadb, ```mysqladmin``` for mysql\
147 | VARNISH_VERSION=```latest``` for centos version 9+ and fedora, ```stable``` for the others\
148 | SSL_SNIPPET=```echo 'Generated Self-signed SSL Certificate for localhost'``` for localhost\
149 | SSL_SNIPPET=```certbot certonly --webroot --webroot-path /tmp/acme-challenge --rsa-key-size 4096 --non-interactive --agree-tos --no-eff-email --force-renewal --email ${LETSENCRYPT_EMAIL} -d ${DOMAIN_NAME} -d www.${DOMAIN_NAME}``` for remotehost
150 |
151 | and
152 |
153 | ```
154 | cp ./phpmyadmin/apache2/sites-available/default-ssl.sample.conf ./phpmyadmin/apache2/sites-available/default-ssl.conf
155 | ```
156 | change example.com to your domain name in ```./phpmyadmin/apache2/sites-available/default-ssl.conf``` file.
157 |
158 | ```
159 | cp ./database/phpmyadmin/sql/create_tables.sql.template.example ./database/phpmyadmin/sql/create_tables.sql.template
160 | ```
161 | change pma_controluser and db_authentication_password in ```./database/phpmyadmin/sql/create_tables.sql.template``` file.
162 |
163 | ### Installation
164 |
165 | Firstly: will create external volume
166 |
167 | ```
168 | docker volume create --driver local --opt type=none --opt device=${PWD}/certbot --opt o=bind certbot-etc
169 | ```
170 |
171 | for localhost ssl: Generate Self-signed SSL Certificate with guide [mkcert repository](https://github.com/FiloSottile/mkcert).
172 |
173 | ```
174 | docker compose up -d
175 | ```
176 |
177 | then reloading for webserver ssl configuration
178 |
179 | ```
180 | docker container restart webserver
181 | ```
182 |
183 | The containers are now built and running. You should be able to access the WordPress installation with the configured IP in the browser address. `https://example.com`.
184 |
185 | For convenience you may add a new entry into your hosts file.
186 |
187 | ## Portainer
188 |
189 | ```
190 | docker compose -f portainer-docker-compose.yml -p portainer up -d
191 | ```
192 |
193 | manage docker with [Portainer](https://www.portainer.io/) is the definitive container management tool for Docker, Docker Swarm with it's highly intuitive GUI and API.
194 |
195 | You can also visit `https://example.com:9001` to access portainer after starting the containers.
196 |
197 | ## Usage
198 |
199 | #### You could manage docker containers without command line with portainer.
200 |
201 | ### Show both running and stopped containers
202 |
203 | The docker ps command only shows running containers by default. To see all containers, use the -a (or --all) flag:
204 |
205 | ```
206 | docker ps -a
207 | ```
208 |
209 | ### Starting containers
210 |
211 | You can start the containers with the `up` command in daemon mode (by adding `-d` as an argument) or by using the `start` command:
212 |
213 | ```
214 | docker compose start
215 | ```
216 |
217 | ### Stopping containers
218 |
219 | ```
220 | docker compose stop
221 | ```
222 |
223 | ### Removing containers
224 |
225 | To stop and remove all the containers use the `down` command:
226 |
227 | ```
228 | docker compose down
229 | ```
230 |
231 | to remove portainer and the other containers:
232 |
233 | ```
234 | docker rm -f $(docker ps -a -q)
235 | ```
236 |
237 | Use `-v` if you need to remove the database volume which is used to persist the database:
238 |
239 | ```
240 | docker compose down -v
241 | ```
242 |
243 | to remove external certbot-etc and portainer and the other volumes:
244 |
245 | ```
246 | docker volume rm $(docker volume ls -q)
247 | ```
248 |
249 | Delete all images, containers, volumes, and networks that are not associated with a container (dangling):
250 |
251 | ```
252 | docker system prune
253 | ```
254 |
255 | To additionally remove any stopped containers and all unused images (not just dangling ones), add the -a flag to the command:
256 |
257 | ```
258 | docker system prune -a
259 | ```
260 |
261 | to remove portainer and the other images:
262 |
263 | ```
264 | docker rmi $(docker image ls -q)
265 | ```
266 |
267 | ### Logs containers
268 |
269 | To fetch the logs of a container.
270 |
271 | ```
272 | docker container logs container_name_or_id
273 | ```
274 |
275 | ### Project from existing source
276 |
277 | Copy all files into a new directory:
278 |
279 | You can now use the `up` command:
280 |
281 | ```
282 | docker compose up -d
283 | ```
284 |
285 | ### Docker run reference
286 |
287 | [https://docs.docker.com/engine/reference/run/](https://docs.docker.com/engine/reference/run/)
288 |
289 | ### Website
290 |
291 | You should see the "Wordpress installation" page in your browser. If not, please check if your PHP installation satisfies WordPress's requirements.
292 |
293 | ```
294 | https://example.com
295 | ```
296 |
297 | add or remove code in the ./php-fpm/php/conf.d/security.ini file for custom php.ini configurations
298 |
299 | [https://www.php.net/manual/en/configuration.file.php](https://www.php.net/manual/en/configuration.file.php)
300 |
301 | You should make changes custom host configurations ```./php-fpm/php-fpm.d/z-www.conf``` then must restart service, FPM uses php.ini syntax for its configuration file - php-fpm.conf, and pool configuration files.
302 |
303 | [https://www.php.net/manual/en/install.fpm.configuration.php](https://www.php.net/manual/en/install.fpm.configuration.php)
304 |
305 | ```
306 | docker container restart wordpress
307 | ```
308 |
309 | add and/or remove wordpress site folders and files with any ftp client program in ```./wordpress``` folder.
310 |
You can also visit `https://example.com` to access website after starting the containers.
311 |
312 | #### Webserver
313 |
314 | add or remove code in the ```./webserver/templates/nginx.conf.template``` file for custom nginx configurations
315 |
316 | [https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/)
317 |
318 | #### Redis Plugin
319 |
320 | add and active [Redis Cache](https://wordpress.org/plugins/redis-cache/) plugin and
321 |
322 | must add below code in wp-config.php file.
323 |
324 | ```
325 | define('WP_REDIS_HOST', 'redis');
326 | define('WP_CACHE_KEY_SALT', 'wp-docker-7f1a7682-9aec-4d4b-9a10-46bbadec41ba');
327 | define('WP_REDIS_PREFIX', $_SERVER['HTTP_HOST']);
328 | define('WP_REDIS_CONFIG', [
329 | 'prefix' => getenv('WP_REDIS_PREFIX') ?: null,
330 | 'timeout' => 0.5,
331 | 'read_timeout' => 0.5,
332 | 'async_flush' => true,
333 | 'compression' => 'zstd',
334 | 'serializer' => 'igbinary',
335 | 'split_alloptions' => true,
336 | 'debug' => false,
337 | 'save_commands' => false,
338 | ]);
339 | ```
340 |
341 | #### Varnish Plugin
342 |
343 | add and active [Proxy Cache Purge](https://wordpress.org/plugins/varnish-http-purge/) plugin.
344 |
345 | #####
346 | Go to the WordPress dashboard
347 | Click on Plugins
348 | Click on Add New
349 | Search for the Redis Cache / the Proxy Cache Purge plugin
350 | Click on Install Now and confirm
351 | Finally, activate the plugin
352 |
353 | add this code to connect always with ssl in wp-config.php file.
354 |
355 | ```
356 | define('FORCE_SSL_LOGIN', true);
357 | define('FORCE_SSL_ADMIN', true);
358 | ```
359 |
360 | after every change in the wordpress and the varnish configuration or if You get error "502 Bad Gateway":
361 |
362 | ```
363 | docker container restart varnish
364 | ```
365 |
366 | ### phpMyAdmin
367 |
368 | You can add your own custom config.inc.php settings (such as Configuration Storage setup) by creating a file named config.user.inc.php with the various user defined settings in it, and then linking it into the container using:
369 |
370 | ```
371 | ./phpmyadmin/config.user.inc.php
372 | ```
373 |
374 | You can also visit `https://example.com:9090` to access phpMyAdmin after starting the containers.
375 |
376 | The first authorize screen(htpasswd;username or password) and phpmyadmin login screen the username and the password is the same as supplied in the `.env` file.
377 |
378 | ### backup
379 |
380 | This will back up the all files and folders in database/dump sql and html volumes, once per day, and write it to ./backups with a filename like backup-2023-01-01T10-18-00.tar.gz
381 |
382 | #### can run on a custom cron schedule
383 |
384 | ```BACKUP_CRON_EXPRESSION: '20 01 * * *'``` the UTC timezone.
385 |
--------------------------------------------------------------------------------
/backups/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/certbot/.certbot.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/damalis/full-stack-nginx-wordpress-for-everyone-with-docker-compose/a3dd37f47be66b77930a7e4416af186279070796/certbot/.certbot.lock
--------------------------------------------------------------------------------
/certbot/ssl-dhparam.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEA3T1FEu1mdoEgqUL/v7OPEGd8yp+/2nUHyRFeyx9UQu7GXWMk7SSC
3 | ob/WE62HKtTiL3GskWJYh5HCPcBOETCWtbeib4xX4x/M7fzRU+io7hraIXPq3f1/
4 | /9KMljeQF8YqX913DU0WbeA8gJrpWEKSTiYkKBoS5K0AfgQDcDv+rHD8vOANfU/h
5 | YtR/Pjidl8TL/64fyWnGLn1l6VMzyYqgxGIlVX51fdwkO1KPpI+nLvURv7iXph3H
6 | WdpZl7wT1kcctjqH84MFBb4CotzUceY/+L3JOtUMkQbf68nB6Fwrx63+9IEYN9of
7 | 0pyDWBhM9NbnJUHZsJEBq49T4FPlMJCiMwIBAg==
8 | -----END DH PARAMETERS-----
9 |
--------------------------------------------------------------------------------
/database/conf.d/z-mysql.cnf:
--------------------------------------------------------------------------------
1 | [client]
2 |
3 | [mysqld]
4 |
5 | [mysqldump]
6 |
7 | [mysql]
8 |
9 | [mysqlhotcopy]
10 |
11 | [mysqld_safe]
12 |
--------------------------------------------------------------------------------
/database/phpmyadmin/sql/create_tables.sql.template.example:
--------------------------------------------------------------------------------
1 | -- --------------------------------------------------------
2 | -- SQL Commands to set up the pmadb as described in the documentation.
3 | --
4 | -- This file is meant for use with MySQL 5 and above!
5 | --
6 | -- This script expects the user pma to already be existing. If we would put a
7 | -- line here to create them too many users might just use this script and end
8 | -- up with having the same password for the controluser.
9 | --
10 | -- This user "pma" must be defined in config.inc.php (controluser/controlpass)
11 | --
12 | -- Please don't forget to set up the tablenames in config.inc.php
13 | --
14 |
15 | -- --------------------------------------------------------
16 |
17 | --
18 | -- Database : `phpmyadmin`
19 | --
20 | CREATE DATABASE IF NOT EXISTS `phpmyadmin`
21 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
22 | USE phpmyadmin;
23 |
24 | -- --------------------------------------------------------
25 |
26 | --
27 | -- CREATE USER IF NOT EXISTS for phpmyadmin database
28 | --
29 | CREATE USER IF NOT EXISTS 'pma_controluser'@'%' IDENTIFIED BY 'db_authentication_password';
30 |
31 | --
32 | -- Privileges
33 | --
34 | -- (activate this statement if necessary)
35 | GRANT SELECT, INSERT, DELETE, UPDATE, ALTER ON `phpmyadmin`.* TO 'pma_controluser'@'%';
36 |
37 | -- --------------------------------------------------------
38 |
39 | --
40 | -- Table structure for table `pma__bookmark`
41 | --
42 |
43 | CREATE TABLE IF NOT EXISTS `pma__bookmark` (
44 | `id` int(10) unsigned NOT NULL auto_increment,
45 | `dbase` varchar(255) NOT NULL default '',
46 | `user` varchar(255) NOT NULL default '',
47 | `label` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
48 | `query` text NOT NULL,
49 | PRIMARY KEY (`id`)
50 | )
51 | COMMENT='Bookmarks'
52 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
53 |
54 | -- --------------------------------------------------------
55 |
56 | --
57 | -- Table structure for table `pma__column_info`
58 | --
59 |
60 | CREATE TABLE IF NOT EXISTS `pma__column_info` (
61 | `id` int(5) unsigned NOT NULL auto_increment,
62 | `db_name` varchar(64) NOT NULL default '',
63 | `table_name` varchar(64) NOT NULL default '',
64 | `column_name` varchar(64) NOT NULL default '',
65 | `comment` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
66 | `mimetype` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
67 | `transformation` varchar(255) NOT NULL default '',
68 | `transformation_options` varchar(255) NOT NULL default '',
69 | `input_transformation` varchar(255) NOT NULL default '',
70 | `input_transformation_options` varchar(255) NOT NULL default '',
71 | PRIMARY KEY (`id`),
72 | UNIQUE KEY `db_name` (`db_name`,`table_name`,`column_name`)
73 | )
74 | COMMENT='Column information for phpMyAdmin'
75 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
76 |
77 | -- --------------------------------------------------------
78 |
79 | --
80 | -- Table structure for table `pma__history`
81 | --
82 |
83 | CREATE TABLE IF NOT EXISTS `pma__history` (
84 | `id` bigint(20) unsigned NOT NULL auto_increment,
85 | `username` varchar(64) NOT NULL default '',
86 | `db` varchar(64) NOT NULL default '',
87 | `table` varchar(64) NOT NULL default '',
88 | `timevalue` timestamp NOT NULL default CURRENT_TIMESTAMP,
89 | `sqlquery` text NOT NULL,
90 | PRIMARY KEY (`id`),
91 | KEY `username` (`username`,`db`,`table`,`timevalue`)
92 | )
93 | COMMENT='SQL history for phpMyAdmin'
94 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
95 |
96 | -- --------------------------------------------------------
97 |
98 | --
99 | -- Table structure for table `pma__pdf_pages`
100 | --
101 |
102 | CREATE TABLE IF NOT EXISTS `pma__pdf_pages` (
103 | `db_name` varchar(64) NOT NULL default '',
104 | `page_nr` int(10) unsigned NOT NULL auto_increment,
105 | `page_descr` varchar(50) COLLATE utf8_general_ci NOT NULL default '',
106 | PRIMARY KEY (`page_nr`),
107 | KEY `db_name` (`db_name`)
108 | )
109 | COMMENT='PDF relation pages for phpMyAdmin'
110 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
111 |
112 | -- --------------------------------------------------------
113 |
114 | --
115 | -- Table structure for table `pma__recent`
116 | --
117 |
118 | CREATE TABLE IF NOT EXISTS `pma__recent` (
119 | `username` varchar(64) NOT NULL,
120 | `tables` text NOT NULL,
121 | PRIMARY KEY (`username`)
122 | )
123 | COMMENT='Recently accessed tables'
124 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
125 |
126 | -- --------------------------------------------------------
127 |
128 | --
129 | -- Table structure for table `pma__favorite`
130 | --
131 |
132 | CREATE TABLE IF NOT EXISTS `pma__favorite` (
133 | `username` varchar(64) NOT NULL,
134 | `tables` text NOT NULL,
135 | PRIMARY KEY (`username`)
136 | )
137 | COMMENT='Favorite tables'
138 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
139 |
140 | -- --------------------------------------------------------
141 |
142 | --
143 | -- Table structure for table `pma__table_uiprefs`
144 | --
145 |
146 | CREATE TABLE IF NOT EXISTS `pma__table_uiprefs` (
147 | `username` varchar(64) NOT NULL,
148 | `db_name` varchar(64) NOT NULL,
149 | `table_name` varchar(64) NOT NULL,
150 | `prefs` text NOT NULL,
151 | `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
152 | PRIMARY KEY (`username`,`db_name`,`table_name`)
153 | )
154 | COMMENT='Tables'' UI preferences'
155 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
156 |
157 | -- --------------------------------------------------------
158 |
159 | --
160 | -- Table structure for table `pma__relation`
161 | --
162 |
163 | CREATE TABLE IF NOT EXISTS `pma__relation` (
164 | `master_db` varchar(64) NOT NULL default '',
165 | `master_table` varchar(64) NOT NULL default '',
166 | `master_field` varchar(64) NOT NULL default '',
167 | `foreign_db` varchar(64) NOT NULL default '',
168 | `foreign_table` varchar(64) NOT NULL default '',
169 | `foreign_field` varchar(64) NOT NULL default '',
170 | PRIMARY KEY (`master_db`,`master_table`,`master_field`),
171 | KEY `foreign_field` (`foreign_db`,`foreign_table`)
172 | )
173 | COMMENT='Relation table'
174 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
175 |
176 | -- --------------------------------------------------------
177 |
178 | --
179 | -- Table structure for table `pma__table_coords`
180 | --
181 |
182 | CREATE TABLE IF NOT EXISTS `pma__table_coords` (
183 | `db_name` varchar(64) NOT NULL default '',
184 | `table_name` varchar(64) NOT NULL default '',
185 | `pdf_page_number` int(11) NOT NULL default '0',
186 | `x` float unsigned NOT NULL default '0',
187 | `y` float unsigned NOT NULL default '0',
188 | PRIMARY KEY (`db_name`,`table_name`,`pdf_page_number`)
189 | )
190 | COMMENT='Table coordinates for phpMyAdmin PDF output'
191 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
192 |
193 | -- --------------------------------------------------------
194 |
195 | --
196 | -- Table structure for table `pma__table_info`
197 | --
198 |
199 | CREATE TABLE IF NOT EXISTS `pma__table_info` (
200 | `db_name` varchar(64) NOT NULL default '',
201 | `table_name` varchar(64) NOT NULL default '',
202 | `display_field` varchar(64) NOT NULL default '',
203 | PRIMARY KEY (`db_name`,`table_name`)
204 | )
205 | COMMENT='Table information for phpMyAdmin'
206 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
207 |
208 | -- --------------------------------------------------------
209 |
210 | --
211 | -- Table structure for table `pma__tracking`
212 | --
213 |
214 | CREATE TABLE IF NOT EXISTS `pma__tracking` (
215 | `db_name` varchar(64) NOT NULL,
216 | `table_name` varchar(64) NOT NULL,
217 | `version` int(10) unsigned NOT NULL,
218 | `date_created` datetime NOT NULL,
219 | `date_updated` datetime NOT NULL,
220 | `schema_snapshot` text NOT NULL,
221 | `schema_sql` text,
222 | `data_sql` longtext,
223 | `tracking` set('UPDATE','REPLACE','INSERT','DELETE','TRUNCATE','CREATE DATABASE','ALTER DATABASE','DROP DATABASE','CREATE TABLE','ALTER TABLE','RENAME TABLE','DROP TABLE','CREATE INDEX','DROP INDEX','CREATE VIEW','ALTER VIEW','DROP VIEW') default NULL,
224 | `tracking_active` int(1) unsigned NOT NULL default '1',
225 | PRIMARY KEY (`db_name`,`table_name`,`version`)
226 | )
227 | COMMENT='Database changes tracking for phpMyAdmin'
228 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
229 |
230 | -- --------------------------------------------------------
231 |
232 | --
233 | -- Table structure for table `pma__userconfig`
234 | --
235 |
236 | CREATE TABLE IF NOT EXISTS `pma__userconfig` (
237 | `username` varchar(64) NOT NULL,
238 | `timevalue` timestamp NOT NULL default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
239 | `config_data` text NOT NULL,
240 | PRIMARY KEY (`username`)
241 | )
242 | COMMENT='User preferences storage for phpMyAdmin'
243 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
244 |
245 | -- --------------------------------------------------------
246 |
247 | --
248 | -- Table structure for table `pma__users`
249 | --
250 |
251 | CREATE TABLE IF NOT EXISTS `pma__users` (
252 | `username` varchar(64) NOT NULL,
253 | `usergroup` varchar(64) NOT NULL,
254 | PRIMARY KEY (`username`,`usergroup`)
255 | )
256 | COMMENT='Users and their assignments to user groups'
257 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
258 |
259 | -- --------------------------------------------------------
260 |
261 | --
262 | -- Table structure for table `pma__usergroups`
263 | --
264 |
265 | CREATE TABLE IF NOT EXISTS `pma__usergroups` (
266 | `usergroup` varchar(64) NOT NULL,
267 | `tab` varchar(64) NOT NULL,
268 | `allowed` enum('Y','N') NOT NULL DEFAULT 'N',
269 | PRIMARY KEY (`usergroup`,`tab`,`allowed`)
270 | )
271 | COMMENT='User groups with configured menu items'
272 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
273 |
274 | -- --------------------------------------------------------
275 |
276 | --
277 | -- Table structure for table `pma__navigationhiding`
278 | --
279 |
280 | CREATE TABLE IF NOT EXISTS `pma__navigationhiding` (
281 | `username` varchar(64) NOT NULL,
282 | `item_name` varchar(64) NOT NULL,
283 | `item_type` varchar(64) NOT NULL,
284 | `db_name` varchar(64) NOT NULL,
285 | `table_name` varchar(64) NOT NULL,
286 | PRIMARY KEY (`username`,`item_name`,`item_type`,`db_name`,`table_name`)
287 | )
288 | COMMENT='Hidden items of navigation tree'
289 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
290 |
291 | -- --------------------------------------------------------
292 |
293 | --
294 | -- Table structure for table `pma__savedsearches`
295 | --
296 |
297 | CREATE TABLE IF NOT EXISTS `pma__savedsearches` (
298 | `id` int(5) unsigned NOT NULL auto_increment,
299 | `username` varchar(64) NOT NULL default '',
300 | `db_name` varchar(64) NOT NULL default '',
301 | `search_name` varchar(64) NOT NULL default '',
302 | `search_data` text NOT NULL,
303 | PRIMARY KEY (`id`),
304 | UNIQUE KEY `u_savedsearches_username_dbname` (`username`,`db_name`,`search_name`)
305 | )
306 | COMMENT='Saved searches'
307 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
308 |
309 | -- --------------------------------------------------------
310 |
311 | --
312 | -- Table structure for table `pma__central_columns`
313 | --
314 |
315 | CREATE TABLE IF NOT EXISTS `pma__central_columns` (
316 | `db_name` varchar(64) NOT NULL,
317 | `col_name` varchar(64) NOT NULL,
318 | `col_type` varchar(64) NOT NULL,
319 | `col_length` text,
320 | `col_collation` varchar(64) NOT NULL,
321 | `col_isNull` boolean NOT NULL,
322 | `col_extra` varchar(255) default '',
323 | `col_default` text,
324 | PRIMARY KEY (`db_name`,`col_name`)
325 | )
326 | COMMENT='Central list of columns'
327 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
328 |
329 | -- --------------------------------------------------------
330 |
331 | --
332 | -- Table structure for table `pma__designer_settings`
333 | --
334 |
335 | CREATE TABLE IF NOT EXISTS `pma__designer_settings` (
336 | `username` varchar(64) NOT NULL,
337 | `settings_data` text NOT NULL,
338 | PRIMARY KEY (`username`)
339 | )
340 | COMMENT='Settings related to Designer'
341 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
342 |
343 | -- --------------------------------------------------------
344 |
345 | --
346 | -- Table structure for table `pma__export_templates`
347 | --
348 |
349 | CREATE TABLE IF NOT EXISTS `pma__export_templates` (
350 | `id` int(5) unsigned NOT NULL AUTO_INCREMENT,
351 | `username` varchar(64) NOT NULL,
352 | `export_type` varchar(10) NOT NULL,
353 | `template_name` varchar(64) NOT NULL,
354 | `template_data` text NOT NULL,
355 | PRIMARY KEY (`id`),
356 | UNIQUE KEY `u_user_type_template` (`username`,`export_type`,`template_name`)
357 | )
358 | COMMENT='Saved export templates'
359 | DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
360 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | wordpress:
4 | depends_on:
5 | database:
6 | condition: service_healthy
7 | image: wordpress:${PHP_IMAGE_NAME}
8 | container_name: wordpress
9 | networks:
10 | - backend
11 | volumes:
12 | - 'html:${WEBSERVER_DOC_ROOT}'
13 | - type: bind
14 | source: ./php-fpm/php/conf.d/security.ini
15 | target: '${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini'
16 | - type: bind
17 | source: ./php-fpm/php-fpm.d/z-www.conf
18 | target: '${PHP_INI_DIR_PREFIX}/php-fpm.d/z-www.conf'
19 | hostname: wordpress
20 | restart: unless-stopped
21 | ports:
22 | - '9000:80'
23 | links:
24 | - database
25 | - redis
26 | healthcheck:
27 | test: ["CMD-SHELL", "/bin/pidof php-fpm > /dev/null || exit 1"]
28 | interval: 5s
29 | timeout: 5s
30 | retries: 20
31 | environment:
32 | WORDPRESS_DB_HOST: 'database'
33 | WORDPRESS_DB_USER: '${WORDPRESS_DB_USER}'
34 | WORDPRESS_DB_PASSWORD: '${WORDPRESS_DB_PASSWORD}'
35 | WORDPRESS_DB_NAME: '${WORDPRESS_DB_NAME}'
36 | WORDPRESS_TABLE_PREFIX: '${WORDPRESS_TABLE_PREFIX}'
37 | HOME: '/tmp'
38 | TZ: '${LOCAL_TIMEZONE}'
39 | labels:
40 | - 'docker-volume-backup.stop-during-backup=true'
41 | command: bash -c "curl -sSL https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions -o - | sh -s redis && grep -qe 'date.timezone = ${LOCAL_TIMEZONE}' ${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini || echo 'date.timezone = ${LOCAL_TIMEZONE}' >> ${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini; docker-entrypoint.sh 'php-fpm'"
42 |
43 | webserver:
44 | depends_on:
45 | - varnish
46 | image: nginx:stable
47 | container_name: webserver
48 | networks:
49 | - backend
50 | - frontend
51 | volumes:
52 | - 'html:${WEBSERVER_DOC_ROOT}'
53 | - type: bind
54 | source: ./webserver/nginx.conf
55 | target: '${NGINX_PREFIX}/nginx.conf'
56 | - type: bind
57 | source: ./webserver/templates/nginx.conf.template
58 | target: '${NGINX_PREFIX}/templates/default.conf.template'
59 | - type: bind
60 | source: ./webserver/ssl-option/options-ssl-nginx.conf
61 | target: '${LETSENCRYPT_CONF_PREFIX}/options-ssl-nginx.conf'
62 | - type: bind
63 | source: ./ssl-conf.sh
64 | target: '/tmp/ssl-conf.sh'
65 | - 'certbot-etc:${LETSENCRYPT_CONF_PREFIX}'
66 | - '/tmp/acme-challenge:/tmp/acme-challenge'
67 | hostname: webserver
68 | restart: unless-stopped
69 | ports:
70 | - '80:80'
71 | - '443:443'
72 | - '90:90'
73 | links:
74 | - wordpress
75 | environment:
76 | NGINX_HOST: ${DOMAIN_NAME}
77 | NGINX_PORT: 80
78 | TZ: '${LOCAL_TIMEZONE}'
79 | command: bash -c "/docker-entrypoint.sh nginx -v; sh /tmp/ssl-conf.sh '${DOMAIN_NAME}' '${LETSENCRYPT_CONF_PREFIX}' '${NGINX_PREFIX}'"
80 |
81 | certbot:
82 | depends_on:
83 | - webserver
84 | image: certbot/certbot:latest
85 | container_name: certbot
86 | networks:
87 | - backend
88 | volumes:
89 | - 'certbot-etc:${LETSENCRYPT_CONF_PREFIX}'
90 | - 'certbot-var:/var/lib/letsencrypt'
91 | - '/tmp/acme-challenge:/tmp/acme-challenge'
92 | restart: unless-stopped
93 | healthcheck:
94 | test: ["CMD-SHELL", "test -d ${LETSENCRYPT_CONF_PREFIX}/live/${DOMAIN_NAME} || exit 1"]
95 | interval: 5s
96 | timeout: 5s
97 | retries: 20
98 | environment:
99 | TZ: '${LOCAL_TIMEZONE}'
100 | entrypoint: /bin/sh -c "${SSL_SNIPPET}; trap exit TERM; while :; do certbot renew --dry-run; sleep 12h & wait $${!}; done;"
101 |
102 | phpmyadmin:
103 | depends_on:
104 | certbot:
105 | condition: service_healthy
106 | image: phpmyadmin:latest
107 | container_name: phpmyadmin
108 | networks:
109 | - backend
110 | - frontend
111 | volumes:
112 | - type: bind
113 | source: ./phpmyadmin/apache2/sites-available/default-ssl.conf
114 | target: '${APACHE_CONFDIR_PREFIX}/sites-available/default-ssl.conf'
115 | - type: bind
116 | source: ./phpmyadmin/apache2/ports.conf
117 | target: '${APACHE_CONFDIR_PREFIX}/ports.conf'
118 | - type: bind
119 | source: ./phpmyadmin/ssl-option/options-ssl-apache.conf
120 | target: '${LETSENCRYPT_CONF_PREFIX}/options-ssl-apache.conf'
121 | - type: bind
122 | source: ./phpmyadmin/config.user.inc.php
123 | target: '${PMA_CONF_FOLDER}/config.user.inc.php'
124 | - type: bind
125 | source: ./phpmyadmin/php/conf.d/security.ini
126 | target: '${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini'
127 | - 'certbot-etc:${LETSENCRYPT_CONF_PREFIX}'
128 | hostname: phpmyadmin
129 | restart: unless-stopped
130 | ports:
131 | - '9090:443'
132 | links:
133 | - database
134 | environment:
135 | PMA_HOST: 'database'
136 | PMA_PMADB: 'phpmyadmin'
137 | PMA_CONTROLUSER: '${PMA_CONTROLUSER}'
138 | PMA_CONTROLPASS: '${PMA_CONTROLPASS}'
139 | MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
140 | UPLOAD_LIMIT: '${PMA_UPLOAD_LIMIT}'
141 | MEMORY_LIMIT: '${PMA_MEMORY_LIMIT}'
142 | TZ: '${LOCAL_TIMEZONE}'
143 | command: >
144 | bash -c "echo ${PMA_HTPASSWD_USERNAME}:phpmyadmin:$$( printf \"%s:%s:%s\" \"${PMA_HTPASSWD_USERNAME}\" \"phpmyadmin\" \"${PMA_HTPASSWD_PASSWORD}\" | md5sum | awk '{print $$1}' ) > ${PMA_CONF_FOLDER}/.htpasswd
145 | && printf 'AuthType Digest\\nAuthName \"phpmyadmin\"\\nAuthDigestProvider file\\nAuthUserFile ${PMA_CONF_FOLDER}/.htpasswd\\nRequire valid-user\\n' > ${WEBSERVER_DOC_ROOT}/.htaccess && a2enmod auth_digest;
146 | mkdir -p ${WEBSERVER_DOC_ROOT}/../upload && chown www-data:www-data ${WEBSERVER_DOC_ROOT}/../upload && chmod a+w ${WEBSERVER_DOC_ROOT}/../upload; mkdir -p ${WEBSERVER_DOC_ROOT}/../save && chown www-data:www-data ${WEBSERVER_DOC_ROOT}/../save && chmod a+w ${WEBSERVER_DOC_ROOT}/../save;
147 | grep -qxF 'ServerName 127.0.0.1' ${APACHE_CONFDIR_PREFIX}/apache2.conf || echo -e '\\nServerName 127.0.0.1' >> ${APACHE_CONFDIR_PREFIX}/apache2.conf; grep -qe 'date.timezone = ${LOCAL_TIMEZONE}' ${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini || echo 'date.timezone = ${LOCAL_TIMEZONE}' >> ${PHP_INI_DIR_PREFIX}/php/conf.d/security.ini;
148 | a2enmod ssl && a2ensite default-ssl && a2dissite 000-default && /docker-entrypoint.sh 'apache2-foreground'"
149 |
150 | database:
151 | image: ${DATABASE_IMAGE_NAME}:${DATABASE_VERSION}
152 | container_name: database
153 | networks:
154 | - backend
155 | volumes:
156 | - 'db:/var/lib/mysql'
157 | - 'db-backup-data:/tmp/backup'
158 | - type: bind
159 | source: ./database/conf.d/z-mysql.cnf
160 | target: '${MYSQL_CONF_PREFIX}/z-mysql.cnf'
161 | - 'phpmyadmin-sql:/docker-entrypoint-initdb.d'
162 | hostname: database
163 | restart: unless-stopped
164 | ports:
165 | - '3306:3306'
166 | healthcheck:
167 | test: ["CMD-SHELL", "${DATABASE_ADMIN_COMMANDLINE} ping --silent || exit 1"]
168 | interval: 5s
169 | timeout: 5s
170 | retries: 50
171 | environment:
172 | MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
173 | MYSQL_DATABASE: '${WORDPRESS_DB_NAME}'
174 | MYSQL_USER: '${WORDPRESS_DB_USER}'
175 | MYSQL_PASSWORD: '${WORDPRESS_DB_PASSWORD}'
176 | MYSQL_ALLOW_EMPTY_PASSWORD: 'No'
177 | MYSQL_ROOT_HOST: '${MYSQL_ROOT_HOST}'
178 | TZ: '${LOCAL_TIMEZONE}'
179 | labels:
180 | - "docker-volume-backup.stop-during-backup=true"
181 | - "docker-volume-backup.archive-pre=/bin/sh -c 'mysqldump -uroot -p${MYSQL_ROOT_PASSWORD} --all-databases > /tmp/backup/db_backup_data.sql'"
182 | - "docker-volume-backup.exec-label=database"
183 | command: bash -c "${DATABASE_PACKAGE_MANAGER} && export PMA_CONTROLUSER=${PMA_CONTROLUSER} export PMA_CONTROLPASS=${PMA_CONTROLPASS} && envsubst '$$PMA_CONTROLUSER,$$PMA_CONTROLPASS' < /docker-entrypoint-initdb.d/create_tables.sql.template > /docker-entrypoint-initdb.d/create_tables.sql && docker-entrypoint.sh --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci"
184 |
185 | redis:
186 | image: redis:latest
187 | container_name: redis
188 | networks:
189 | - backend
190 | volumes:
191 | - 'dtredis:/data'
192 | - type: bind
193 | source: ./redis
194 | target: '${REDIS_CONF_PREFIX}/redis'
195 | hostname: redis
196 | sysctls:
197 | - net.core.somaxconn=512
198 | restart: unless-stopped
199 | ports:
200 | - '6379:6379'
201 | environment:
202 | ALLOW_EMPTY_PASSWORD: 'yes'
203 | TZ: '${LOCAL_TIMEZONE}'
204 | command: "redis-server ${REDIS_CONF_PREFIX}/redis/redis.conf"
205 |
206 | varnish:
207 | depends_on:
208 | wordpress:
209 | condition: service_healthy
210 | image: varnish:${VARNISH_VERSION}
211 | container_name: varnish
212 | networks:
213 | - backend
214 | volumes:
215 | - type: bind
216 | source: ./varnish/default.vcl
217 | target: '${VARNISH_CONF_PREFIX}/default.vcl'
218 | hostname: varnish
219 | tmpfs:
220 | - /var/lib/varnish:exec
221 | restart: unless-stopped
222 | ports:
223 | - '8080:80'
224 | environment:
225 | VARNISH_SIZE: '${VARNISH_SIZE}'
226 | TZ: '${LOCAL_TIMEZONE}'
227 | command: "-a http=:8080,HTTP -p default_ttl=3600 -n /tmp/varnish_workdir"
228 |
229 | backup:
230 | image: offen/docker-volume-backup:latest
231 | container_name: backup
232 | networks:
233 | - backend
234 | volumes:
235 | - 'html:/backup/html:ro'
236 | - 'db:/backup/db:ro'
237 | - 'db-backup-data:/backup/db-backup-data:ro'
238 | - '/var/run/docker.sock:/var/run/docker.sock:ro'
239 | - type: bind
240 | source: ./backups
241 | target: /archive
242 | hostname: backup
243 | restart: unless-stopped
244 | environment:
245 | BACKUP_CRON_EXPRESSION: '20 01 * * *'
246 | BACKUP_FILENAME: 'backup-%Y-%m-%dT%H-%M-%S.tar.gz'
247 | BACKUP_RETENTION_DAYS: '7'
248 | EXEC_LABEL: 'database'
249 | BACKUP_EXCLUDE_REGEXP: 'wp-admin|wp-includes|\\.log$$'
250 |
251 | networks:
252 | backend: null
253 | frontend: null
254 |
255 | volumes:
256 | html:
257 | name: wordpress-html
258 | driver: local
259 | driver_opts:
260 | type: none
261 | device: ${DIRECTORY_PATH}/wordpress
262 | o: bind
263 | db:
264 | name: ${DATABASE_CONT_NAME}-data
265 | db-backup-data:
266 | name: ${DATABASE_CONT_NAME}-backup-data
267 | phpmyadmin-sql:
268 | name: phpmyadmin-sql
269 | driver: local
270 | driver_opts:
271 | type: none
272 | device: ${DIRECTORY_PATH}/database/phpmyadmin/sql
273 | o: bind
274 | dtredis:
275 | name: redis-data
276 | certbot-etc:
277 | external: true
278 | certbot-var:
279 | name: certbot-var
280 |
--------------------------------------------------------------------------------
/env.example:
--------------------------------------------------------------------------------
1 | WEBSERVER_DOC_ROOT=/var/www/html
2 | NGINX_PREFIX=/etc/nginx
3 | LOCAL_TIMEZONE=local_timezone
4 | DOMAIN_NAME=example.com
5 | DIRECTORY_PATH=directory_path
6 |
7 | LETSENCRYPT_EMAIL=email@domain.com
8 | LETSENCRYPT_CONF_PREFIX=/etc/letsencrypt
9 | SSL_SNIPPET=ssl_snippet
10 |
11 | PHP_IMAGE_NAME=php8.3-fpm
12 | PHP_INI_DIR_PREFIX=/usr/local/etc
13 |
14 | WORDPRESS_DB_USER=db_username
15 | WORDPRESS_DB_PASSWORD=db_password
16 | WORDPRESS_DB_NAME=db_name
17 | WORDPRESS_TABLE_PREFIX=db_table_prefix
18 |
19 | MYSQL_CONF_PREFIX=/etc/mysql/conf.d
20 | MYSQL_ROOT_PASSWORD=mysql_root_password
21 | MYSQL_ROOT_HOST=%
22 | DATABASE_IMAGE_NAME=which_db
23 | DATABASE_CONT_NAME=which_db
24 | DATABASE_VERSION=latest
25 | DATABASE_PACKAGE_MANAGER=db_package_manager
26 | DATABASE_ADMIN_COMMANDLINE=db_admin_commandline
27 |
28 | PMA_CONTROLUSER=pma_username
29 | PMA_CONTROLPASS=pma_password
30 | PMA_CONF_FOLDER=/etc/phpmyadmin
31 | PMA_HTPASSWD_USERNAME=db_username
32 | PMA_HTPASSWD_PASSWORD=db_password
33 | PMA_UPLOAD_LIMIT=8M
34 | PMA_MEMORY_LIMIT=-1
35 | APACHE_CONFDIR_PREFIX=/etc/apache2
36 |
37 | REDIS_CONF_PREFIX=/usr/local/etc
38 |
39 | VARNISH_VERSION=varnish_version
40 | VARNISH_CONF_PREFIX=/etc/varnish
41 | VARNISH_SIZE=2G
42 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | clear
4 | echo ""
5 | echo "======================================================================="
6 | echo "| |"
7 | echo "| full-stack-nginx-wordpress-for-everyone-with-docker-compose |"
8 | echo "| by Erdal ALTIN |"
9 | echo "| |"
10 | echo "======================================================================="
11 | sleep 2
12 |
13 | # the "lpms" is an abbreviation of Linux Package Management System
14 | lpms=""
15 | for i in apk dnf yum apt zypper pacman
16 | do
17 | if [ -x "$(command -v $i)" ]; then
18 | if [ "$i" == "apk" ]
19 | then
20 | lpms=$i
21 | sudo apk add --no-cache --upgrade grep
22 | break
23 | elif [ "$i" == "dnf" ] && ([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "fedora" ]] || (([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') != "centos" ]] && [[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"fedora"* ]]) || ([[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"rhel"* ]] && [ $(sudo uname -m) == "s390x" ])))
24 | then
25 | lpms=$i
26 | break
27 | elif [ "$i" == "yum" ] && ([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "centos" ]] || (([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') != "fedora" ]] && [[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"fedora"* ]]) || ([[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"rhel"* ]] && [ $(sudo uname -m) == "s390x" ])))
28 | then
29 | lpms=$i
30 | break
31 | elif [ "$i" == "apt" ] && ([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == *"ubuntu"* ]] || [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == *"debian"* ]] || [[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"ubuntu"* ]] || [[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release | tr -d '"') == *"debian"* ]])
32 | then
33 | lpms=$i
34 | break
35 | elif [[ $(grep -Pow 'ID_LIKE=\K[^;]*' /etc/os-release) == *"suse"* ]]
36 | then
37 | lpms=$i
38 | break
39 | elif [ "$i" == "pacman" ]
40 | then
41 | lpms=$i
42 | break
43 | fi
44 | fi
45 | done
46 |
47 | if [ -z $lpms ]; then
48 | echo ""
49 | echo "could not be detected package management system"
50 | echo ""
51 | exit 0
52 | fi
53 |
54 | ##########
55 | # set varnish version
56 | ##########
57 | varnish_version="stable"
58 | if ([[ $(grep -Pow 'VERSION_ID=\K[^;]*' /etc/os-release | tr -d '"') == 9* ]] && [ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "centos" ]) || [ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "fedora" ]
59 | then
60 | varnish_version="latest"
61 | fi
62 |
63 | ##########
64 | # Uninstall old versions
65 | ##########
66 | echo ""
67 | echo ""
68 | echo "======================================================================="
69 | echo "| Older versions of Docker were called docker, docker.io, or docker-engine."
70 | echo "| If these are installed or all conflicting packages, uninstall them."
71 | echo "======================================================================="
72 | echo ""
73 | sleep 2
74 |
75 | # linux remove command for pms
76 | if [ "$lpms" == "apk" ]
77 | then
78 | sudo apk del docker podman-docker
79 | elif [ "$lpms" == "dnf" ]
80 | then
81 | sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
82 | elif [ "$lpms" == "yum" ]
83 | then
84 | sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc
85 | elif [ "$lpms" == "apt" ]
86 | then
87 | for pkg in docker docker-engine docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt remove $pkg; done
88 | elif [ "$lpms" == "zypper" ]
89 | then
90 | if [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == *"sles"* ]]
91 | then
92 | sudo zypper remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine runc
93 | fi
94 | elif [ "$lpms" == "pacman" ]
95 | then
96 | sudo pacman -Rssn podman-docker podman-compose
97 | else
98 | echo ""
99 | echo "could not be detected package management system"
100 | echo ""
101 | exit 0
102 | fi
103 |
104 | echo ""
105 | echo "Done ✓"
106 | echo "======================================================================="
107 |
108 | ##########
109 | # Install Docker
110 | ##########
111 | echo ""
112 | echo ""
113 | echo "======================================================================="
114 | echo "| Install Docker..."
115 | echo "======================================================================="
116 | echo ""
117 | sleep 2
118 |
119 | if [ "$lpms" == "apk" ]
120 | then
121 | sudo apk add --update docker openrc bind-tools
122 | sudo rc-update add docker boot
123 | sudo service docker start
124 | elif [ "$lpms" == "dnf" ]
125 | then
126 | sudo dnf -y install dnf-plugins-core
127 | if [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "fedora" ]] || ([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "rhel" ]] && [ $(sudo uname -m) == "s390x" ])
128 | then
129 | sudo dnf config-manager --add-repo https://download.docker.com/linux/$(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"')/docker-ce.repo
130 | sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin bind-utils
131 | elif [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') != "rhel" ]]
132 | then
133 | sudo dnf install docker
134 | else
135 | echo ""
136 | echo "unsupport operation system and/or architecture"
137 | echo ""
138 | exit 0
139 | fi
140 | elif [ "$lpms" == "yum" ]
141 | then
142 | sudo yum install -y yum-utils
143 | if [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "centos" ]] || ([[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == "rhel" ]] && [ $(sudo uname -m) == "s390x" ])
144 | then
145 | sudo yum-config-manager --add-repo https://download.docker.com/linux/$(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"')/docker-ce.repo
146 | sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin bind-utils
147 | elif [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') != "rhel" ]]
148 | then
149 | sudo yum install docker
150 | else
151 | echo ""
152 | echo "unsupport operation system and/or architecture"
153 | echo ""
154 | exit 0
155 | fi
156 | elif [ "$lpms" == "zypper" ]
157 | then
158 | if [[ $(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') == *"sles"* ]] && [ $(sudo uname -m) == "s390x" ]
159 | then
160 | # "https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/security:SELinux.repo"
161 | sudo zypper addrepo "https://download.opensuse.org/repositories/security/$(grep -Pow 'VERSION_ID=\K[^;]*' /etc/os-release | tr -d '"')/security.repo"
162 | sudo zypper addrepo https://download.docker.com/linux/sles/docker-ce.repo
163 | sudo zypper install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
164 | else
165 | sudo SUSEConnect -p sle-module-containers/$(sudo uname -s)/$(sudo uname -m) -r ''
166 | sudo zypper install docker
167 | fi
168 |
169 | #Installed=`sudo zypper search --installed-only -v docker | sed -n '6p' | cut -c 28-40`
170 | #Candidate=`sudo zypper info docker | sed -n '10p' | cut -c 18-`
171 | elif [ "$lpms" == "apt" ]
172 | then
173 | sudo apt update
174 | sudo apt install ca-certificates curl gnupg lsb-release
175 | sudo mkdir -m 0755 /etc/apt/keyrings
176 | sudo curl -fsSL https://download.docker.com/linux/$(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"')/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
177 | sudo chmod a+r /etc/apt/keyrings/docker.gpg
178 | # Add the repository to Apt sources:
179 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(grep -Pow 'ID=\K[^;]*' /etc/os-release | tr -d '"') $(grep -Po 'VERSION_CODENAME=\K[^;]*' /etc/os-release) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
180 | sudo apt update
181 | sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
182 |
183 | #Installed=`sudo apt-cache policy docker-ce | sed -n '2p' | cut -c 14-`
184 | #Candidate=`sudo apt-cache policy docker-ce | sed -n '3p' | cut -c 14-`
185 | elif [ "$lpms" == "pacman" ]
186 | then
187 | sudo pacman -Syu --noconfirm
188 | sudo pacman -Ss docker docker-buildx
189 | else
190 | echo ""
191 | echo "could not be detected package management system"
192 | echo ""
193 | exit 0
194 | fi
195 |
196 | #sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
197 | #if [[ "$Installed" != "$Candidate" ]]; then
198 | # sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
199 | #elif [[ "$Installed" == "$Candidate" ]]; then
200 | # echo ""
201 | # echo 'docker currently version already installed.'
202 | #fi
203 |
204 | if [ $? -ne 0 ]
205 | then
206 | exit 0
207 | fi
208 |
209 | if [ $lpms != "apk" ]
210 | then
211 | sudo systemctl enable docker.service
212 | sudo systemctl enable containerd.service
213 | sudo systemctl start docker
214 | fi
215 |
216 | echo ""
217 | echo "Done ✓"
218 | echo "======================================================================="
219 |
220 | ##########
221 | # Run Docker without sudo rights
222 | ##########
223 | echo ""
224 | echo ""
225 | echo "======================================================================="
226 | echo "| Running Docker without sudo rights..."
227 | echo "======================================================================="
228 | echo ""
229 | sleep 2
230 |
231 | sudo groupadd docker
232 | sudo usermod -aG docker ${USER}
233 | # su - ${USER} &
234 |
235 | echo ""
236 | echo "Done ✓"
237 | echo "======================================================================="
238 |
239 | ##########
240 | # Install Docker Compose
241 | ##########
242 | echo ""
243 | echo ""
244 | echo "======================================================================="
245 | echo "| Installing Docker Compose v2.32.4..."
246 | echo "======================================================================="
247 | echo ""
248 | sleep 2
249 |
250 | sudo mkdir -p /usr/local/lib/docker/cli-plugins
251 | sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/lib/docker/cli-plugins/docker-compose
252 | sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
253 |
254 | echo ""
255 | echo "Done ✓"
256 | echo "======================================================================="
257 |
258 | ##########
259 | # permission for Docker daemon socket
260 | ##########
261 | echo ""
262 | echo ""
263 | echo "======================================================================="
264 | echo "| permission for Docker daemon socket..."
265 | echo "======================================================================="
266 | echo ""
267 | sleep 2
268 |
269 | sudo chmod 666 /var/run/docker.sock
270 |
271 | echo ""
272 | echo "Done ✓"
273 | echo "======================================================================="
274 |
275 | clear
276 | ##########
277 | # Setup project variables
278 | ##########
279 | echo ""
280 | echo "======================================================================="
281 | echo "| Please enter project related variables..."
282 | echo "======================================================================="
283 | echo ""
284 | sleep 2
285 |
286 | # set the host
287 | which_h=""
288 | items=("localhost" "remotehost")
289 | PS3="which computer command line are you on? Select the host: "
290 | select h in "${items[@]}"
291 | do
292 | case $REPLY in
293 | 1)
294 | which_h=$h
295 | break;;
296 | 2)
297 | which_h=$h
298 | break;;
299 | *)
300 | echo "Invalid choice $REPLY";;
301 | esac
302 | done
303 | echo "Ok."
304 |
305 | # set your domain name
306 | if [ "$which_h" == "localhost" ]
307 | then
308 | read -p 'Enter Domain Name(default : localhost or e.g. : example.com): ' domain_name
309 | : ${domain_name:=localhost}
310 | [ "$domain_name" != "localhost" ] && sudo -- sh -c -e "grep -Eq '$domain_name' /etc/hosts || echo '127.0.0.1 $domain_name' >> /etc/hosts"
311 | else
312 | domain_name=""
313 | read -p 'Enter Domain Name(e.g. : example.com): ' domain_name
314 | #[ "$domain_name" != "localhost" ] && sudo -- sh -c -e "sed -i '/$domain_name/d' /etc/hosts"
315 | fi
316 | [ -z $domain_name ] && domain_name="NULL"
317 | host -N 0 $domain_name 2>&1 > /dev/null
318 | while [ $? -ne 0 ]
319 | do
320 | echo "Try again"
321 | sudo -- sh -c -e "sed -i '/$domain_name/d' /etc/hosts"
322 | if [ "$which_h" == "localhost" ]
323 | then
324 | read -p 'Enter Domain Name(default : localhost or e.g. : example.com): ' domain_name
325 | : ${domain_name:=localhost}
326 | [ "$domain_name" != "localhost" ] && sudo -- sh -c -e "grep -Eq '$domain_name' /etc/hosts || echo '127.0.0.1 $domain_name' >> /etc/hosts"
327 | else
328 | read -p 'Enter Domain Name(e.g. : example.com): ' domain_name
329 | #[ "$domain_name" != "localhost" ] && sudo -- sh -c -e "sed -i '/$domain_name/d' /etc/hosts"
330 | fi
331 | [ -z $domain_name ] && domain_name="NULL"
332 | host -N 0 $domain_name 2>&1 > /dev/null
333 | done
334 | echo "Ok."
335 |
336 | ssl_snippet=""
337 | if [ "$which_h" == "localhost" ]
338 | then
339 | ssl_snippet="echo 'Generated Self-signed SSL Certificate for localhost'"
340 | if [ "$lpms" == "apk" ]
341 | then
342 | sudo apk add --no-cache nss-tools go git
343 | elif [ "$lpms" == "dnf" ]
344 | then
345 | sudo dnf install nss-tools go git
346 | elif [ "$lpms" == "yum" ]
347 | then
348 | sudo yum install nss-tools go git
349 | elif [ "$lpms" == "zypper" ]
350 | then
351 | sudo zypper install mozilla-nss-tools go git
352 | elif [ "$lpms" == "apt" ]
353 | then
354 | sudo apt install libnss3-tools go git
355 | elif [ "$lpms" == "pacman" ]
356 | then
357 | sudo pacman -S nss go git
358 | else
359 | echo ""
360 | echo "could not be detected package management system"
361 | echo ""
362 | exit 0
363 | fi
364 | sudo rm -Rf mkcert && git clone https://github.com/FiloSottile/mkcert && cd mkcert && go build -ldflags "-X main.Version=$(git describe --tags)"
365 | sudo mkcert -uninstall && mkcert -install && mkcert -key-file privkey.pem -cert-file chain.pem $domain_name *.$domain_name && sudo cat privkey.pem chain.pem > fullchain.pem && sudo mkdir -p ../certbot/live/$domain_name && sudo mv *.pem ../certbot/live/$domain_name && cd ..
366 | echo "Ok."
367 | else
368 | ssl_snippet="certbot certonly --webroot --webroot-path \/tmp\/acme-challenge --rsa-key-size 4096 --non-interactive --agree-tos --no-eff-email --force-renewal --email \$\{LETSENCRYPT_EMAIL\} -d \$\{DOMAIN_NAME\} -d www.\$\{DOMAIN_NAME\}"
369 | fi
370 |
371 | # set parameters in env.example file
372 | email=""
373 | regex="^[a-zA-Z0-9\._-]+\@[a-zA-Z0-9._-]+\.[a-zA-Z]+\$"
374 | read -p 'Enter Email Address for letsencrypt ssl(e.g. : email@domain.com): ' email
375 | while [ -z $email ] || [[ ! $email =~ $regex ]]
376 | do
377 | echo "Try again"
378 | read -p 'Enter Email Address for letsencrypt ssl(e.g. : email@domain.com): ' email
379 | sleep 1
380 | done
381 | echo "Ok."
382 |
383 | db_username=""
384 | db_regex="^[0-9a-zA-Z\$_]{6,}$"
385 | read -p 'Enter Database Username(at least 6 characters): ' db_username
386 | while [[ ! $db_username =~ $db_regex ]]
387 | do
388 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dollar sign and underscore)"
389 | read -p 'Enter Database Username(at least 6 characters): ' db_username
390 | sleep 1
391 | done
392 | echo "Ok."
393 |
394 | db_password=""
395 | password_regex="^[a-zA-Z0-9\._-]{6,}$"
396 | read -p 'Enter Database Password(at least 6 characters): ' db_password
397 | while [[ ! $db_password =~ $password_regex ]]
398 | do
399 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dot, underscore and minus sign)"
400 | read -p 'Enter Database Password(at least 6 characters): ' db_password
401 | sleep 1
402 | done
403 | echo "Ok."
404 |
405 | db_name=""
406 | read -p 'Enter Database Name(at least 6 characters): ' db_name
407 | while [[ ! $db_name =~ $db_regex ]]
408 | do
409 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dollar sign and underscore)"
410 | read -p 'Enter Database Name(at least 6 characters): ' db_name
411 | sleep 1
412 | done
413 | echo "Ok."
414 |
415 | db_table_prefix_regex="^[0-9a-zA-Z\$_]{3,}$"
416 | read -p 'Enter Database Table Prefix(at least 3 characters, default : wp_): ' db_table_prefix
417 | : ${db_table_prefix:=wp_}
418 | while [[ ! $db_table_prefix =~ $db_table_prefix_regex ]]
419 | do
420 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dollar sign and underscore)"
421 | read -p 'Enter Database Table Prefix(at least 3 characters, default : wp_): ' db_table_prefix
422 | : ${db_table_prefix:=wp_}
423 | sleep 1
424 | done
425 | echo "Ok."
426 |
427 | mysql_root_password=""
428 | read -p 'Enter MariaDb/Mysql Root Password(at least 6 characters): ' mysql_root_password
429 | while [[ ! $mysql_root_password =~ $password_regex ]]
430 | do
431 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dot, underscore and minus sign)"
432 | read -p 'Enter MariaDb/Mysql Root Password(at least 6 characters): ' mysql_root_password
433 | sleep 1
434 | done
435 | echo "Ok."
436 |
437 | pma_username=""
438 | read -p 'Enter PhpMyAdmin Username(at least 6 characters): ' pma_username
439 | while [[ ! $pma_username =~ $db_regex ]]
440 | do
441 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dollar sign and underscore)"
442 | read -p 'Enter PhpMyAdmin Username(at least 6 characters): ' pma_username
443 | sleep 1
444 | done
445 | echo "Ok."
446 |
447 | pma_password=""
448 | read -p 'Enter PhpMyAdmin Password(at least 6 characters): ' pma_password
449 | while [[ ! $pma_password =~ $password_regex ]]
450 | do
451 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, dot, underscore and minus sign)"
452 | read -p 'Enter PhpMyAdmin Password(at least 6 characters): ' pma_password
453 | sleep 1
454 | done
455 | echo "Ok."
456 |
457 | which_db=""
458 | db_authentication_password=$pma_password
459 | db_package_manager="apt-get update \&\& apt-get install -y gettext-base"
460 | db_admin_commandline="mariadb-admin"
461 | PS3="Select the database: "
462 | select db in mariadb mysql
463 | do
464 | which_db=$db
465 | if [ $REPLY -eq 2 ]
466 | then
467 | db_package_manager="microdnf install -y gettext"
468 | db_admin_commandline="mysqladmin"
469 | fi
470 | if [ $REPLY -eq 1 ] || [ $REPLY -eq 2 ]
471 | then
472 | break
473 | else
474 | PS3="Select the database: "
475 | fi
476 | done
477 | echo "Ok."
478 |
479 | local_timezone_regex="^[a-zA-Z0-9/+_-]{1,}$"
480 | read -p 'Enter container local Timezone(default : America/Los_Angeles, to see the other timezones, https://docs.diladele.com/docker/timezones.html): ' local_timezone
481 | : ${local_timezone:=America/Los_Angeles}
482 | while [[ ! $local_timezone =~ $local_timezone_regex ]]
483 | do
484 | echo "Try again (can only contain numerals 0-9, basic Latin letters, both lowercase and uppercase, positive, minus sign and underscore)"
485 | read -p 'Enter container local Timezone(default : America/Los_Angeles, to see the other local timezones, https://docs.diladele.com/docker/timezones.html): ' local_timezone
486 | sleep 1
487 | : ${local_timezone:=America/Los_Angeles}
488 | done
489 | local_timezone=${local_timezone//[\/]/\\\/}
490 | echo "Ok."
491 |
492 | read -p "Apply changes (y/n)? " choice
493 | case "$choice" in
494 | y|Y ) clear; echo ""; echo "Yes! Proceeding now...";;
495 | n|N ) echo "No! Aborting now..."; exit 0;;
496 | * ) echo "Invalid input! Aborting now..."; exit 0;;
497 | esac
498 |
499 | \cp ./phpmyadmin/apache2/sites-available/default-ssl.sample.conf ./phpmyadmin/apache2/sites-available/default-ssl.conf
500 | \cp ./database/phpmyadmin/sql/create_tables.sql.template.example ./database/phpmyadmin/sql/create_tables.sql.template
501 |
502 | \cp env.example .env
503 |
504 | sed -i "s/db_authentication_password/${db_authentication_password}/" ./database/phpmyadmin/sql/create_tables.sql.template
505 | sed -i "s|db_package_manager|${db_package_manager}|" .env
506 | sed -i 's/db_admin_commandline/'$db_admin_commandline'/' .env
507 | sed -i 's/example.com/'$domain_name'/' .env
508 | sed -i 's/example.com/'$domain_name'/g' ./phpmyadmin/apache2/sites-available/default-ssl.conf
509 | sed -i 's/email@domain.com/'$email'/' .env
510 | sed -i "s/ssl_snippet/$ssl_snippet/" .env
511 | sed -i 's/which_db/'$which_db'/g' .env
512 | sed -i 's/db_username/'$db_username'/g' .env
513 | sed -i 's/db_password/'$db_password'/g' .env
514 | sed -i 's/db_name/'$db_name'/' .env
515 | sed -i 's/db_table_prefix/'$db_table_prefix'/' .env
516 | sed -i 's/mysql_root_password/'$mysql_root_password'/' .env
517 | sed -i 's/pma_username/'$pma_username'/' .env
518 | sed -i 's/pma_password/'$pma_password'/' .env
519 | sed -i 's/pma_controluser/'$pma_username'/g' ./database/phpmyadmin/sql/create_tables.sql.template
520 | sed -i "s@directory_path@$(pwd)@" .env
521 | sed -i 's/local_timezone/'$local_timezone'/' .env
522 | sed -i 's/varnish_version/'$varnish_version'/' .env
523 |
524 | if [ -x "$(command -v docker)" ] && [ "$(docker compose version)" ]; then
525 | # Firstly: create external volume
526 | docker volume create --driver local --opt type=none --opt device=`pwd`/certbot --opt o=bind certbot-etc > /dev/null
527 | # installing WordPress and the other services
528 | docker compose up -d & export pid=$!
529 | echo "WordPress and the other services installing proceeding..."
530 | echo ""
531 | wait $pid
532 | if [ $? -eq 0 ]
533 | then
534 | # installing portainer
535 | docker compose -f portainer-docker-compose.yml -p portainer up -d & export pid=$!
536 | echo ""
537 | echo "portainer installing proceeding..."
538 | wait $pid
539 | if [ $? -ne 0 ]; then
540 | echo "Error! could not installed portainer" >&2
541 | exit 1
542 | else
543 | echo ""
544 | until [ -n "$(sudo find ./certbot/live -name '$domain_name' 2>/dev/null | head -1)" ]; do
545 | echo "waiting for Let's Encrypt certificates for $domain_name"
546 | sleep 5s & wait ${!}
547 | if sudo [ -d "./certbot/live/$domain_name" ]; then break; fi
548 | done
549 | echo "Ok."
550 | #until [ ! -z `docker compose ps -a --filter "status=running" --services | grep webserver` ]; do
551 | # echo "waiting starting webserver container"
552 | # sleep 2s & wait ${!}
553 | # if [ ! -z `docker compose ps -a --filter "status=running" --services | grep webserver` ]; then break; fi
554 | #done
555 | echo ""
556 | echo "Reloading webserver ssl configuration"
557 | docker container restart webserver > /dev/null 2>&1
558 | echo "Ok."
559 | echo ""
560 | echo "completed setup"
561 | echo ""
562 | echo "Website: https://$domain_name"
563 | echo "Portainer: https://$domain_name:9001"
564 | echo "phpMyAdmin: https://$domain_name:9090"
565 | echo ""
566 | echo "Ok."
567 | fi
568 | else
569 | echo ""
570 | echo "Error! could not installed WordPress and the other services with docker compose" >&2
571 | echo ""
572 | exit 1
573 | fi
574 | else
575 | echo ""
576 | echo "not found docker and/or docker compose, Install docker and/or docker compose" >&2
577 | echo ""
578 | exit 1
579 | fi
580 |
--------------------------------------------------------------------------------
/php-fpm/php-fpm.d/z-www.conf:
--------------------------------------------------------------------------------
1 | [www]
2 | php_flag[display_errors] = off
3 |
4 |
--------------------------------------------------------------------------------
/php-fpm/php/conf.d/security.ini:
--------------------------------------------------------------------------------
1 | max_execution_time = 60
2 | memory_limit = 3072M
3 | post_max_size = 8M
4 | upload_max_filesize = 8M
5 | max_input_time = 60
6 | file_uploads = On
7 | safe_mode = Off
8 | max_input_vars = 1000
9 | cgi.fix_pathinfo = 0
10 |
--------------------------------------------------------------------------------
/phpmyadmin/apache2/ports.conf:
--------------------------------------------------------------------------------
1 | # If you just change the port or add more ports here, you will likely also
2 | # have to change the VirtualHost statement in
3 | # /etc/apache2/sites-enabled/000-default.conf
4 |
5 | # Listen 80
6 |
7 |
8 | Listen 443
9 |
10 |
11 |
12 | Listen 443
13 |
14 |
15 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
16 |
--------------------------------------------------------------------------------
/phpmyadmin/apache2/sites-available/000-default.conf:
--------------------------------------------------------------------------------
1 |
2 | # The ServerName directive sets the request scheme, hostname and port that
3 | # the server uses to identify itself. This is used when creating
4 | # redirection URLs. In the context of virtual hosts, the ServerName
5 | # specifies what hostname must appear in the request's Host: header to
6 | # match this virtual host. For the default virtual host (this file) this
7 | # value is not decisive as it is used as a last resort host regardless.
8 | # However, you must set it for any further virtual host explicitly.
9 | ServerName example.com
10 |
11 | ServerAdmin webmaster@localhost
12 | DocumentRoot /var/www/html
13 |
14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
15 | # error, crit, alert, emerg.
16 | # It is also possible to configure the loglevel for particular
17 | # modules, e.g.
18 | #LogLevel info ssl:warn
19 |
20 | ErrorLog ${APACHE_LOG_DIR}/error.log
21 | CustomLog ${APACHE_LOG_DIR}/access.log combined
22 |
23 | # For most configuration files from conf-available/, which are
24 | # enabled or disabled at a global level, it is possible to
25 | # include a line for only one particular virtual host. For example the
26 | # following line enables the CGI configuration for this host only
27 | # after it has been globally disabled with "a2disconf".
28 | #Include conf-available/serve-cgi-bin.conf
29 |
30 |
31 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
32 |
--------------------------------------------------------------------------------
/phpmyadmin/apache2/sites-available/default-ssl.sample.conf:
--------------------------------------------------------------------------------
1 |
2 |
3 | ServerAdmin info@example.com
4 | ServerName example.com
5 | ServerAlias *.example.com
6 |
7 | Protocols h2 http/1.1
8 |
9 | DocumentRoot /var/www/html
10 |
11 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
12 | # error, crit, alert, emerg.
13 | # It is also possible to configure the loglevel for particular
14 | # modules, e.g.
15 | #LogLevel info ssl:warn
16 |
17 | ErrorLog ${APACHE_LOG_DIR}/error.log
18 | CustomLog ${APACHE_LOG_DIR}/access.log combined
19 |
20 | # For most configuration files from conf-available/, which are
21 | # enabled or disabled at a global level, it is possible to
22 | # include a line for only one particular virtual host. For example the
23 | # following line enables the CGI configuration for this host only
24 | # after it has been globally disabled with "a2disconf".
25 | #Include conf-available/serve-cgi-bin.conf
26 |
27 | # SSL Engine Switch:
28 | # Enable/Disable SSL for this virtual host.
29 | SSLEngine on
30 |
31 | # A self-signed (snakeoil) certificate can be created by installing
32 | # the ssl-cert package. See
33 | # /usr/share/doc/apache2/README.Debian.gz for more info.
34 | # If both key and certificate are stored in the same file, only the
35 | # SSLCertificateFile directive is needed.
36 | SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
37 | SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
38 |
39 | # Server Certificate Chain:
40 | # Point SSLCertificateChainFile at a file containing the
41 | # concatenation of PEM encoded CA certificates which form the
42 | # certificate chain for the server certificate. Alternatively
43 | # the referenced file can be the same as SSLCertificateFile
44 | # when the CA certificates are directly appended to the server
45 | # certificate for convinience.
46 | SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
47 |
48 | # Certificate Authority (CA):
49 | # Set the CA certificate verification path where to find CA
50 | # certificates for client authentication or alternatively one
51 | # huge file containing all of them (file must be PEM encoded)
52 | # Note: Inside SSLCACertificatePath you need hash symlinks
53 | # to point to the certificate files. Use the provided
54 | # Makefile to update the hash symlinks after changes.
55 | #SSLCACertificatePath /etc/ssl/certs/
56 | #SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
57 |
58 | # Certificate Revocation Lists (CRL):
59 | # Set the CA revocation path where to find CA CRLs for client
60 | # authentication or alternatively one huge file containing all
61 | # of them (file must be PEM encoded)
62 | # Note: Inside SSLCARevocationPath you need hash symlinks
63 | # to point to the certificate files. Use the provided
64 | # Makefile to update the hash symlinks after changes.
65 | #SSLCARevocationPath /etc/apache2/ssl.crl/
66 | #SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
67 |
68 | # Client Authentication (Type):
69 | # Client certificate verification type and depth. Types are
70 | # none, optional, require and optional_no_ca. Depth is a
71 | # number which specifies how deeply to verify the certificate
72 | # issuer chain before deciding the certificate is not valid.
73 | #SSLVerifyClient require
74 | #SSLVerifyDepth 10
75 |
76 | # SSL Engine Options:
77 | # Set various options for the SSL engine.
78 | # o FakeBasicAuth:
79 | # Translate the client X.509 into a Basic Authorisation. This means that
80 | # the standard Auth/DBMAuth methods can be used for access control. The
81 | # user name is the `one line' version of the client's X.509 certificate.
82 | # Note that no password is obtained from the user. Every entry in the user
83 | # file needs this password: `xxj31ZMTZzkVA'.
84 | # o ExportCertData:
85 | # This exports two additional environment variables: SSL_CLIENT_CERT and
86 | # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
87 | # server (always existing) and the client (only existing when client
88 | # authentication is used). This can be used to import the certificates
89 | # into CGI scripts.
90 | # o StdEnvVars:
91 | # This exports the standard SSL/TLS related `SSL_*' environment variables.
92 | # Per default this exportation is switched off for performance reasons,
93 | # because the extraction step is an expensive operation and is usually
94 | # useless for serving static content. So one usually enables the
95 | # exportation for CGI and SSI requests only.
96 | # o OptRenegotiate:
97 | # This enables optimized SSL connection renegotiation handling when SSL
98 | # directives are used in per-directory context.
99 | SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
100 |
101 | SSLOptions +StdEnvVars
102 |
103 |
104 | SSLOptions +StdEnvVars
105 |
106 |
107 | # SSL Protocol Adjustments:
108 | # The safe and default but still SSL/TLS standard compliant shutdown
109 | # approach is that mod_ssl sends the close notify alert but doesn't wait for
110 | # the close notify alert from client. When you need a different shutdown
111 | # approach you can use one of the following variables:
112 | # o ssl-unclean-shutdown:
113 | # This forces an unclean shutdown when the connection is closed, i.e. no
114 | # SSL close notify alert is send or allowed to received. This violates
115 | # the SSL/TLS standard but is needed for some brain-dead browsers. Use
116 | # this when you receive I/O errors because of the standard approach where
117 | # mod_ssl sends the close notify alert.
118 | # o ssl-accurate-shutdown:
119 | # This forces an accurate shutdown when the connection is closed, i.e. a
120 | # SSL close notify alert is send and mod_ssl waits for the close notify
121 | # alert of the client. This is 100% SSL/TLS standard compliant, but in
122 | # practice often causes hanging connections with brain-dead browsers. Use
123 | # this only for browsers where you know that their SSL implementation
124 | # works correctly.
125 | # Notice: Most problems of broken clients are also related to the HTTP
126 | # keep-alive facility, so you usually additionally want to disable
127 | # keep-alive for those clients, too. Use variable "nokeepalive" for this.
128 | # Similarly, one has to force some clients to use HTTP/1.0 to workaround
129 | # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
130 | # "force-response-1.0" for this.
131 | # BrowserMatch "MSIE [2-6]" \
132 | # nokeepalive ssl-unclean-shutdown \
133 | # downgrade-1.0 force-response-1.0
134 |
135 | Include /etc/letsencrypt/options-ssl-apache.conf
136 |
137 |
138 |
139 |
140 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
141 |
--------------------------------------------------------------------------------
/phpmyadmin/config.user.inc.php:
--------------------------------------------------------------------------------
1 | /dev/null ]; then
10 | openssl dhparam -out $2/ssl-dhparam.pem 2048
11 | fi
12 |
13 | use_lets_encrypt_certificates() {
14 | echo "switching webserver to use Let's Encrypt certificate for $1"
15 | sed '/#location.\/./,/#}/ s/#//; s/#listen/listen/g; s/#ssl_/ssl_/g' $3/conf.d/default.conf > $3/conf.d/default.conf.bak
16 | }
17 |
18 | reload_webserver() {
19 | cp $1/conf.d/default.conf.bak $1/conf.d/default.conf
20 | rm $1/conf.d/default.conf.bak
21 | echo "Starting webserver nginx service"
22 | nginx -t
23 | }
24 |
25 | wait_for_lets_encrypt() {
26 | if [ -d "$2/live/$1" ]; then
27 | break
28 | else
29 | until [ -d "$2/live/$1" ]; do
30 | echo "waiting for Let's Encrypt certificates for $1"
31 | sleep 5s & wait ${!}
32 | if [ -d "$2/live/$1" ]; then break; fi
33 | done
34 | fi;
35 | use_lets_encrypt_certificates "$1" "$2" "$3"
36 | reload_webserver "$3"
37 | }
38 |
39 | if [ ! -d "$2/live/$1" ]; then
40 | wait_for_lets_encrypt "$1" "$2" "$3" &
41 | else
42 | use_lets_encrypt_certificates "$1" "$2" "$3"
43 | reload_webserver "$3"
44 | fi
45 |
46 | nginx -g 'daemon off;'
47 |
--------------------------------------------------------------------------------
/varnish/default.vcl:
--------------------------------------------------------------------------------
1 | vcl 4.1;
2 |
3 | import std;
4 |
5 | backend default {
6 | .host = "webserver";
7 | .port = "90";
8 | .connect_timeout = 2s;
9 | }
10 |
11 | # Add hostnames, IP addresses and subnets that are allowed to purge content
12 | acl purge {
13 | "webserver";
14 | "wordpress";
15 | "localhost";
16 | "127.0.0.1";
17 | "::1";
18 | }
19 |
20 | sub vcl_recv {
21 | # Remove empty query string parameters
22 | # e.g.: www.example.com/index.html?
23 | if (req.url ~ "\?$") {
24 | set req.url = regsub(req.url, "\?$", "");
25 | }
26 |
27 | # Remove port number from host header
28 | set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
29 |
30 | # Sorts query string parameters alphabetically for cache normalization purposes
31 | set req.url = std.querysort(req.url);
32 |
33 | # Remove the proxy header to mitigate the httpoxy vulnerability
34 | # See https://httpoxy.org/
35 | unset req.http.proxy;
36 |
37 | # Purge logic to remove objects from the cache.
38 | # Tailored to the Proxy Cache Purge WordPress plugin
39 | # See https://wordpress.org/plugins/varnish-http-purge/
40 | if(req.method == "PURGE") {
41 | if(!client.ip ~ purge) {
42 | return(synth(405,"PURGE not allowed for this IP address"));
43 | }
44 | if (req.http.X-Purge-Method == "regex") {
45 | ban("obj.http.x-url ~ " + req.url + " && obj.http.x-host == " + req.http.host);
46 | return(synth(200, "Purged"));
47 | }
48 | ban("obj.http.x-url == " + req.url + " && obj.http.x-host == " + req.http.host);
49 | return(synth(200, "Purged"));
50 | }
51 |
52 | # Only handle relevant HTTP request methods
53 | if (
54 | req.method != "GET" &&
55 | req.method != "HEAD" &&
56 | req.method != "PUT" &&
57 | req.method != "POST" &&
58 | req.method != "PATCH" &&
59 | req.method != "TRACE" &&
60 | req.method != "OPTIONS" &&
61 | req.method != "DELETE"
62 | ) {
63 | return (pipe);
64 | }
65 |
66 | # Remove tracking query string parameters used by analytics tools
67 | if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
68 | set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
69 | set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
70 | set req.url = regsub(req.url, "\?&", "?");
71 | set req.url = regsub(req.url, "\?$", "");
72 | }
73 |
74 | # Only cache GET and HEAD requests
75 | if (req.method != "GET" && req.method != "HEAD") {
76 | set req.http.X-Cacheable = "NO:REQUEST-METHOD";
77 | return(pass);
78 | }
79 |
80 | # Mark static files with the X-Static-File header, and remove any cookies
81 | # X-Static-File is also used in vcl_backend_response to identify static files
82 | if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
83 | set req.http.X-Static-File = "true";
84 | unset req.http.Cookie;
85 | return(hash);
86 | }
87 |
88 | # No caching of special URLs, logged in users and some plugins
89 | if (
90 | req.http.Cookie ~ "wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordpress_logged_in_|comment_author|PHPSESSID" ||
91 | req.http.Authorization ||
92 | req.url ~ "add_to_cart" ||
93 | req.url ~ "edd_action" ||
94 | req.url ~ "nocache" ||
95 | req.url ~ "^/addons" ||
96 | req.url ~ "^/bb-admin" ||
97 | req.url ~ "^/bb-login.php" ||
98 | req.url ~ "^/bb-reset-password.php" ||
99 | req.url ~ "^/cart" ||
100 | req.url ~ "^/checkout" ||
101 | req.url ~ "^/control.php" ||
102 | req.url ~ "^/login" ||
103 | req.url ~ "^/logout" ||
104 | req.url ~ "^/lost-password" ||
105 | req.url ~ "^/my-account" ||
106 | req.url ~ "^/product" ||
107 | req.url ~ "^/register" ||
108 | req.url ~ "^/register.php" ||
109 | req.url ~ "^/server-status" ||
110 | req.url ~ "^/signin" ||
111 | req.url ~ "^/signup" ||
112 | req.url ~ "^/stats" ||
113 | req.url ~ "^/wc-api" ||
114 | req.url ~ "^/wp-admin" ||
115 | req.url ~ "^/wp-comments-post.php" ||
116 | req.url ~ "^/wp-cron.php" ||
117 | req.url ~ "^/wp-login.php" ||
118 | req.url ~ "^/wp-activate.php" ||
119 | req.url ~ "^/wp-mail.php" ||
120 | req.url ~ "^/wp-login.php" ||
121 | req.url ~ "^\?add-to-cart=" ||
122 | req.url ~ "^\?wc-api=" ||
123 | req.url ~ "^/preview=" ||
124 | req.url ~ "^/\.well-known/acme-challenge/"
125 | ) {
126 | set req.http.X-Cacheable = "NO:Logged in/Got Sessions";
127 | if(req.http.X-Requested-With == "XMLHttpRequest") {
128 | set req.http.X-Cacheable = "NO:Ajax";
129 | }
130 | return(pass);
131 | }
132 |
133 | # Remove x-cache-status header
134 | unset req.http.x-cache-status;
135 |
136 | # Remove any cookies left
137 | unset req.http.Cookie;
138 | return(hash);
139 | }
140 |
141 | sub vcl_hash {
142 | if(req.http.X-Forwarded-Proto) {
143 | # Create cache variations depending on the request protocol
144 | hash_data(req.http.X-Forwarded-Proto);
145 | }
146 | }
147 |
148 | sub vcl_hit {
149 | set req.http.x-cache-status = "HIT";
150 | if (obj.ttl <= 0s && obj.grace > 0s) {
151 | set req.http.x-cache-status = "HIT graced";
152 | }
153 |
154 | if (req.method == "PURGE") {
155 | return(synth(200, "OK"));
156 | }
157 | }
158 |
159 | sub vcl_miss {
160 | set req.http.x-cache-status = "MISS";
161 |
162 | if (req.method == "PURGE") {
163 | return(synth(404, "Not cached"));
164 | }
165 | }
166 |
167 | sub vcl_pass {
168 | set req.http.x-cache-status = "PASS";
169 | }
170 |
171 | sub vcl_pipe {
172 | set req.http.x-cache-status = "pipe uncacheable";
173 | }
174 |
175 | sub vcl_synth {
176 | set req.http.x-cache-status = "synth synth";
177 | # uncomment the following line to show the information in the response
178 | set resp.http.x-cache-status = req.http.x-cache-status;
179 |
180 | # redirect for http
181 | if (resp.status == 750) {
182 | set resp.status = 301;
183 | set resp.http.Location = req.http.x-redir;
184 | return(deliver);
185 | }
186 | }
187 |
188 | sub vcl_backend_response {
189 | # Inject URL & Host header into the object for asynchronous banning purposes
190 | set beresp.http.x-url = bereq.url;
191 | set beresp.http.x-host = bereq.http.host;
192 |
193 | # If we dont get a Cache-Control header from the backend
194 | # we default to 1h cache for all objects
195 | if (!beresp.http.Cache-Control) {
196 | set beresp.ttl = 1h;
197 | set beresp.http.X-Cacheable = "YES:Forced";
198 | }
199 |
200 | # If the file is marked as static we cache it for 1 day
201 | if (bereq.http.X-Static-File == "true") {
202 | unset beresp.http.Set-Cookie;
203 | set beresp.http.X-Cacheable = "YES:Forced";
204 | set beresp.ttl = 1d;
205 | }
206 |
207 | # Remove the Set-Cookie header when a specific Wordfence cookie is set
208 | if (beresp.http.Set-Cookie ~ "wfvt_|wordfence_verifiedHuman") {
209 | unset beresp.http.Set-Cookie;
210 | }
211 |
212 | if (beresp.http.Set-Cookie) {
213 | set beresp.http.X-Cacheable = "NO:Got Cookies";
214 | } elseif(beresp.http.Cache-Control ~ "private") {
215 | set beresp.http.X-Cacheable = "NO:Cache-Control=private";
216 | }
217 | }
218 |
219 | sub vcl_deliver {
220 | # oh noes backend is down
221 | if (resp.status == 503) {
222 | return(restart);
223 | }
224 |
225 | # Debug header
226 | if(req.http.X-Cacheable) {
227 | set resp.http.X-Cacheable = req.http.X-Cacheable;
228 | } elseif(obj.uncacheable) {
229 | if(!resp.http.X-Cacheable) {
230 | set resp.http.X-Cacheable = "NO:UNCACHEABLE";
231 | }
232 | } elseif(!resp.http.X-Cacheable) {
233 | set resp.http.X-Cacheable = "YES";
234 | }
235 |
236 | set resp.http.x-cache-status = req.http.x-cache-status;
237 | set resp.http.x-varnish = resp.http.x-varnish + " " + req.http.x-cache-status;
238 |
239 | # Cleanup of headers
240 | unset resp.http.x-url;
241 | unset resp.http.x-host;
242 | }
243 |
--------------------------------------------------------------------------------
/webserver/nginx.conf:
--------------------------------------------------------------------------------
1 | user nginx;
2 | worker_processes auto;
3 |
4 | error_log /var/log/nginx/error.log warn;
5 | pid /var/run/nginx.pid;
6 |
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 |
13 | http {
14 | include /etc/nginx/mime.types;
15 | default_type application/octet-stream;
16 |
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 |
21 | access_log /var/log/nginx/access.log main;
22 |
23 | sendfile on;
24 | #tcp_nopush on;
25 |
26 | keepalive_timeout 65;
27 |
28 | #gzip on;
29 |
30 | include /etc/nginx/conf.d/*.conf;
31 | }
--------------------------------------------------------------------------------
/webserver/ssl-option/options-ssl-nginx.conf:
--------------------------------------------------------------------------------
1 | ssl_session_cache shared:le_nginx_SSL:1m;
2 | ssl_session_timeout 1440m;
3 |
4 | ssl_protocols TLSv1.2 TLSv1.3;
5 | ssl_prefer_server_ciphers on;
6 | ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
7 |
8 | # add_header Strict-Transport-Security "max-age=31536000" always;
9 | # add_header Content-Security-Policy upgrade-insecure-requests;
10 | ssl_stapling on;
11 | ssl_stapling_verify on;
12 | resolver 127.0.0.11;
13 |
--------------------------------------------------------------------------------
/webserver/templates/nginx.conf.template:
--------------------------------------------------------------------------------
1 | upstream docker_wordpress {
2 | server wordpress:9000;
3 | }
4 |
5 | upstream docker_varnish {
6 | server varnish:8080;
7 | }
8 |
9 | map $scheme $proxy_x_forwarded_ssl {
10 | default off;
11 | https on;
12 | }
13 |
14 | server {
15 | listen ${NGINX_PORT} default_server;
16 | listen [::]:${NGINX_PORT} ipv6only=on default_server;
17 | #
18 | server_name ${NGINX_HOST} www.${NGINX_HOST};
19 | #
20 | location ~ ^/.well-known/acme-challenge/ {
21 | root /tmp/acme-challenge;
22 | }
23 | #
24 | #location / {
25 | #port_in_redirect off;
26 | #return 301 https://$host$request_uri;
27 | #}
28 | }
29 |
30 | server {
31 | #listen 443 ssl;
32 | #listen [::]:443 ipv6only=on ssl;
33 | #
34 | server_name ${NGINX_HOST} www.${NGINX_HOST};
35 | #
36 | #ssl_certificate /etc/letsencrypt/live/${NGINX_HOST}/fullchain.pem;
37 | #ssl_certificate_key /etc/letsencrypt/live/${NGINX_HOST}/privkey.pem;
38 | #ssl_trusted_certificate /etc/letsencrypt/live/${NGINX_HOST}/chain.pem;
39 | #ssl_dhparam /etc/letsencrypt/ssl-dhparam.pem;
40 | include /etc/letsencrypt/options-ssl-nginx.conf;
41 | #
42 | client_max_body_size 8m;
43 | proxy_headers_hash_max_size 768;
44 | proxy_headers_hash_bucket_size 128;
45 | #
46 |
47 | location / {
48 | proxy_pass http://docker_varnish;
49 | proxy_set_header X-Real-IP $remote_addr;
50 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
51 | proxy_set_header X-Forwarded-Proto $scheme;
52 | proxy_set_header Host $host;
53 | proxy_set_header X-Forwarded-Host $host;
54 | proxy_set_header X-Forwarded-Port $server_port;
55 | proxy_set_header Upgrade $http_upgrade;
56 | proxy_set_header Connection "Upgrade";
57 | proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
58 |
59 | #
60 | proxy_redirect off;
61 | proxy_buffering on;
62 | proxy_buffer_size 128k;
63 | proxy_buffers 100 8k;
64 | proxy_connect_timeout 90;
65 | proxy_send_timeout 90;
66 | proxy_read_timeout 90;
67 | proxy_request_buffering off;
68 | #
69 | # Mitigate httpoxy attack
70 | proxy_set_header Proxy "";
71 | }
72 | #
73 | access_log off;
74 | error_log /var/log/nginx/${NGINX_HOST}-443.error.log error;
75 | }
76 |
77 | server {
78 | #listen 90;
79 | #
80 | server_name ${NGINX_HOST} www.${NGINX_HOST};
81 | #
82 |
83 | root /var/www/html;
84 | index index.php;
85 |
86 | location / {
87 | try_files $uri $uri/ /index.php$is_args$args;
88 | }
89 |
90 | location ~ \.php$ {
91 | #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
92 | include fastcgi_params;
93 | fastcgi_intercept_errors on;
94 | fastcgi_pass docker_wordpress;
95 | #The following parameter can be also included in fastcgi_params file
96 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
97 | }
98 | #
99 | #
100 | # deny access to .htaccess vb. files, if Apache's document root
101 | location ~/\. {
102 | deny all;
103 | log_not_found off;
104 | }
105 | #
106 | location = /favicon.ico {
107 | log_not_found off;
108 | access_log off;
109 | }
110 | #
111 | location = /robots.txt {
112 | allow all;
113 | log_not_found off;
114 | access_log off;
115 | }
116 | #
117 | access_log off;
118 | error_log /var/log/nginx/${NGINX_HOST}-90.error.log error;
119 | }
120 |
--------------------------------------------------------------------------------
/wordpress/README.md:
--------------------------------------------------------------------------------
1 | # WordPress
2 |
3 | add and/or remove wordpress themes, plugins or custom code folders and files with any ftp client program to ./wordpress folder
4 |
./wordpress/wp-config.php file is located in the root of your WordPress file directory and contains your website’s base configuration details, such as database connection information.
5 | You can set custom configuration for your website in this file.
--------------------------------------------------------------------------------