74 Commits

Author SHA1 Message Date
Code-Egg 9c15e82d30 revert docker-compose.yml 2026-01-14 16:30:27 +08:00
E.L. 7ffe1b1547 Merge pull request #105 from stealthinnovative/master
Update to the current versions of OLS 1.8.5, PHP lsphp85, Maria DB 11.8 LTS
2026-01-14 08:38:02 +08:00
stealthinnovative f1ade81793 Update README.md
Updated maridb notes: Latest Stable version: 11.8 LTS
2026-01-13 08:54:15 -10:00
stealthinnovative 2a29d83389 Update .env
Updated OLS version to the current version 1.8.5. Updated php version to the current version lsphp85
2026-01-13 08:53:12 -10:00
stealthinnovative fce090ab61 Update docker-compose.yml
Updated DB service to mariadb from mysql, updated PMA_Host to match. Updated mariadb image to mariadb:11.8 for current LTS version.
2026-01-13 08:52:10 -10:00
Code-Egg 4d6a31859b modified: bin/acme.sh 2025-12-19 15:32:52 +08:00
E.L. 803eb2428f Merge pull request #103 from ducladev/enhancement/mkcert-ssl-config-handling
Enhance SSL configuration handling in mkcert.sh
2025-11-07 09:35:20 +08:00
Anh Duc Le 37c05a177e Enhance SSL configuration handling in mkcert.sh
- Added a check to see if the domain is already configured for SSL before copying certificates.
- Updated messages to clarify the steps of moving domains between 'docker' and 'dockerLocal' templates.
2025-11-06 14:59:14 +07:00
Code-Egg 48e7c948b6 modified: README.md
modified:   bin/mkcert.sh
2025-11-06 14:41:01 +08:00
E.L. 5d1aae3315 Merge pull request #102 from ducladev/feature/local-ssl-with-mkcert
Add mkcert-based local SSL support for virtual hosts
2025-11-06 13:23:22 +08:00
Anh Duc Le 4e41befe7b Update help message in mkcert.sh to clarify usage of --remove option 2025-11-06 10:17:29 +07:00
Anh Duc Le a11d61c5a2 Add mkcert usage instructions for local development SSL in README.md 2025-11-05 11:13:42 +07:00
Anh Duc Le 08f2b45f5a Refactor installation steps in mkcert.sh for clarity and consistency 2025-11-05 10:55:01 +07:00
Anh Duc Le 4a4ced1a28 Add domain verification and local SSL configuration to mkcert.sh 2025-11-05 10:55:01 +07:00
Anh Duc Le 8e480f3768 Enhance mkcert.sh script with improved error handling, added test option, and refined SSL configuration steps 2025-11-05 10:55:01 +07:00
Anh Duc Le 40edce0d1f Add mkcert.sh script for SSL certificate generation and management 2025-11-05 10:55:01 +07:00
E.L. d073ce662a Merge pull request #100 from ducladev/chore/update-readme-format-and-phpmyadmin-link
Update README.md for improved formatting and phpMyAdmin link correction
2025-10-24 14:15:55 +08:00
Anh Duc Le 4e94a92300 Update README.md for improved formatting and phpMyAdmin link correction 2025-10-24 11:15:16 +07:00
Code-Egg 91df8b2fa7 modified: .travis/verify.sh 2025-10-24 08:19:44 +08:00
E.L. 37f437a441 Merge pull request #99 from ducladev/chore/update-phpmyadmin-config-and-version
Update phpMyAdmin configuration and image version in docker-compose
2025-10-23 21:08:28 +08:00
Anh Duc Le 533e28be9e Update phpMyAdmin configuration and image version in docker-compose 2025-10-23 14:34:51 +07:00
Code-Egg fa3fe091ff Update LSCWP config 2025-05-07 10:59:53 +08:00
Code-Egg d94611b2f6 modified: docker-compose.yml 2025-03-07 10:25:02 +08:00
Code-Egg 0a7d0ceed7 modified: .travis/verify.sh
modified:   README.md
2024-11-08 14:31:06 +08:00
Code-Egg 88223ae123 modified: bin/container/domainctl.sh 2024-11-05 21:46:58 +08:00
Code-Egg 54c684df31 Merge branch 'master' of github.com:litespeedtech/ols-docker-env 2024-11-04 09:16:15 +08:00
Code-Egg 6714d56979 replaced mysql command with mariadb command because mariadb docker image doesnt ship with mysql anymore
From https://github.com/litespeedtech/ols-docker-env/pull/86
2024-11-04 09:15:30 +08:00
E.L. ab5bb0f44b Merge pull request #87 from litespeedtech/revert-86-master
Revert "Update database.sh"
2024-10-25 13:50:26 +08:00
E.L. e2f3df1867 Revert "Update database.sh" 2024-10-25 13:49:59 +08:00
E.L. 27c364ca1b Merge pull request #86 from Liangyiu/master
Update database.sh
2024-10-25 13:47:19 +08:00
Marcel 2977b4c0dc Update database.sh
replaced mysql command with mariadb command because mariadb docker image doesnt ship with mysql anymore
2024-10-24 20:02:59 +02:00
Code-Egg 84f1235740 modified: .github/workflows/docker.yml 2024-10-02 10:07:48 +08:00
Code-Egg 2d7b0589fb modified: .env
modified:   README.md
	modified:   docker-compose.yml
2024-10-02 09:53:32 +08:00
E.L 7b5a79e835 Merge pull request #81 from DuCun/master
Update OWASP version
2024-06-19 16:52:16 +08:00
对望 8cfa0dccb7 Update OWASP version 2024-06-19 11:15:58 +08:00
Code-Egg c450986c70 modified: .env 2024-05-15 13:50:47 +08:00
Code-Egg af62ec62c6 Update OWASP config and version 2024-05-07 10:41:26 +08:00
E.L 464d999936 Merge pull request #73 from heathchyi/patch-1
Update docker-compose.yml
2024-03-04 13:51:52 +08:00
Chyi b95f8c6299 Update docker-compose.yml
In the /bin/webadmin.sh file, CONT_NAME='litespeed' is used to check if the Litespeed docker container is running. 
https://github.com/litespeedtech/ols-docker-env/blob/d7b39ddeb46e454d413ce9e3fc80678384b0c8a2/bin/webadmin.sh#L2

Because the docker-compose file does not explicitly specify the container name for Litespeed, newcomers following the steps in the readme.md might encounter an error indicating that Litespeed is not running, which could be confusing. It is recommended to explicitly define a container name in the docker-compose example file that matches the hardcoded container name in the shell script.
2024-03-04 10:57:33 +08:00
E.L d7b39ddeb4 Merge pull request #72 from DuCun/master
Can give it a try, remove logging
2024-02-13 14:47:50 +08:00
对望 ad9252e9b1 Remove logging
Remove logging to prevent 'Error response from daemon: configured logging driver does not support reading' from being booted
2024-01-29 19:01:54 +08:00
E.L 64a15d46cd Merge pull request #71 from worino/patch-1
updated ols_version to latest
2024-01-28 08:49:37 +08:00
Ulrich Dyhr Ottosen 1bbc5c926e updated ols_version to latest 2024-01-27 22:16:06 +01:00
Code-Egg 5d2435e066 modified: .env
modified:   README.md
	modified:   bin/database.sh
2024-01-03 15:32:23 +08:00
E.L 3ee0c984ac Merge pull request #68 from travistran1989/master
add redis container and support database deletion
2024-01-03 15:21:58 +08:00
Travis Tran 51e96582c9 add delete database script 2023-12-21 16:44:12 +07:00
Travis Tran ad99711392 include redis 2023-11-01 20:10:00 +07:00
Cold-Egg 3ca69edb9b Update OWASP rule version 2023-03-04 21:47:26 +08:00
Cold-Egg 55b742ae33 Fix cache for Theme 2023
modified:   bin/container/appinstallctl.sh
2022-12-06 15:51:48 +08:00
Cold-Egg 1a6a67579a Use docker compose instead of docker-compose
modified:   README.md
	modified:   bin/acme.sh
	modified:   bin/appinstall.sh
	modified:   bin/database.sh
	modified:   bin/demosite.sh
	modified:   bin/domain.sh
	modified:   bin/webadmin.sh
2022-10-26 20:44:37 +08:00
Cold-Egg aeafac6022 modified: README.md 2022-10-21 11:51:07 +08:00
Cold-Egg b4fadc0834 Update phpmyadmin 2022-10-04 09:24:23 +08:00
Cold-Egg 82731d9abb Merge branch 'master' of https://github.com/litespeedtech/ols-docker-env 2022-09-02 11:48:56 +08:00
Cold-Egg 5940aaf163 modified: .env
modified:   bin/container/owaspctl.sh
2022-09-02 11:44:53 +08:00
E.L b367f8229e Merge pull request #47 from worino/master
Added network section to docker-compose.yml
2022-08-03 21:54:16 -04:00
Ulrich Dyhr Ottosen 1e980ee5ba updated PHP to version 8.1.x 2022-08-02 20:53:50 +02:00
Ulrich Dyhr Ottosen f52a09ade8 Added network section to ensure all containers are on same network, this helps laravel applications to migrate 2022-08-02 20:29:52 +02:00
E.L d7a0906ac7 Merge pull request #46 from tynanbe/mysql_port
Don't publish MySQL port
2022-07-26 22:12:17 -04:00
tynanbe d4b29af451 Don't publish MySQL port 2022-07-26 13:39:11 -05:00
E.L 3be989d74a Merge pull request #43 from travistran1989/add-revoke-remove
add revoke and remove function
2022-06-13 10:41:16 +08:00
Travis Tran 2943f6c8c3 add revoke and remove function 2022-06-08 16:54:20 +07:00
E.L cfacb6947f Merge pull request #42 from travistran1989/add-ssl-renewal
Add SSL renewal option, set none to log driver
2022-06-06 13:39:23 +08:00
Travis Tran 577a60d075 allow dynamic -f parameter 2022-06-05 22:37:44 +07:00
Travis Tran 70e7048ad4 default turn off docker logger to prevent unnecessary logs 2022-06-03 00:27:37 +07:00
Travis Tran 268eb44035 add ssl renwal 2022-06-03 00:23:54 +07:00
E.L 4c416cbc87 Merge pull request #38 from psavva/unix-lf
Ensure that files have the correct character encoding.
2022-03-15 13:14:23 +08:00
Panayiotis Savva 58c5497dcc fix unix 2022-03-12 11:16:32 +02:00
Cold-Egg 886811221f env update 2022-03-10 11:27:37 +08:00
Cold-Egg 96cfb22867 force mail 2021-06-24 14:51:07 +08:00
Cold-Egg 51712ae88e lsphp80, fix sql 2021-06-09 15:56:26 +08:00
Cold-Egg f0a85ad8a8 workflow 2021-03-08 16:02:27 +08:00
Cold-Egg e6cfccaf2a fix slack url 2020-11-04 15:07:39 +08:00
Cold-Egg 9ba335ea58 add restart always 2020-10-26 15:19:52 +08:00
Cold-Egg 2b7f32d4a3 env update 2020-09-24 12:04:14 +08:00
19 changed files with 1062 additions and 601 deletions
+5 -4
View File
@@ -1,8 +1,9 @@
TimeZone=America/New_York
OLS_VERSION=1.6.13
PHP_VERSION=lsphp74
OLS_VERSION=1.8.5
PHP_VERSION=lsphp85
PHPMYADMIN_VERSION=5.2.3
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_DATABASE=wordpress
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=wordpress
MYSQL_PASSWORD=password
MYSQL_PASSWORD=your_password
DOMAIN=localhost
+20
View File
@@ -0,0 +1,20 @@
#
# Configure line ending normalisation for this repository.
# See http://schacon.github.io/git/gitattributes.html for more information.
#
# Also each developer should configure the old style normalisation on her workstation
# (see http://timclem.wordpress.com/2012/03/01/mind-the-end-of-your-line/):
#
# Windows user should use: git config --global core.autocrlf = true
# Unix/Linux users should use: git config --global core.autocrlf = input
#
# Auto detect text files and perform LF normalization
* text=auto
*.txt text
*.xml text diff=xml
# Shell scripts require LF
*.sh text eol=lf
# Batch scripts require CRLF
*.bat text eol=crlf
+28
View File
@@ -0,0 +1,28 @@
name: docker-build
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup
run: |
docker compose version
docker compose up -d
docker image ls
sleep 10
- name: Verify
run: bash .travis/verify.sh
- name: Clean up
run: |
docker compose stop
docker compose rm -f
+2 -1
View File
@@ -1,4 +1,5 @@
data
latest.yml
config
lsws/conf
lsws/conf
certs
View File
+59 -8
View File
@@ -1,6 +1,7 @@
#!/bin/bash
set -o errexit
EX_DM='example.com'
install_demo(){
./bin/demosite.sh
@@ -22,6 +23,7 @@ verify_page(){
echo '[O] http://localhost:80/'
else
echo '[X] http://localhost:80/'
curl -sIk http://localhost:80/
exit 1
fi
curl -sIk https://localhost:443/ | grep -i WordPress
@@ -29,6 +31,7 @@ verify_page(){
echo '[O] https://localhost:443/'
else
echo '[X] https://localhost:443/'
curl -sIk https://localhost:443/
exit 1
fi
}
@@ -40,20 +43,68 @@ verify_phpadmin(){
else
echo '[X] http://localhost:8080/'
exit 1
fi
curl -sIk https://localhost:8443/ | grep -i phpMyAdmin
if [ ${?} = 0 ]; then
echo '[O] http://localhost:8443/'
else
echo '[X] http://localhost:8443/'
exit 1
fi
fi
}
verify_add_vh_wp(){
echo "Setup a WordPress site with ${EX_DM} domain"
bash bin/domain.sh --add "${EX_DM}"
bash bin/database.sh --domain "${EX_DM}"
bash bin/appinstall.sh --app wordpress --domain "${EX_DM}"
curl -sIk http://${EX_DM}:80/ --resolve ${EX_DM}:80:127.0.0.1 | grep -i WordPress
if [ ${?} = 0 ]; then
echo "[O] http://${EX_DM}:80/"
else
echo "[X] http://${EX_DM}:80/"
curl -sIk http://${EX_DM}:80/
exit 1
fi
}
verify_del_vh_wp(){
echo "Remove ${EX_DM} domain"
bash bin/domain.sh --del ${EX_DM}
if [ ${?} = 0 ]; then
echo "[O] ${EX_DM} VH is removed"
else
echo "[X] ${EX_DM} VH is not removed"
exit 1
fi
echo "Remove examplecom DataBase"
bash bin/database.sh --delete -DB examplecom
}
verify_owasp(){
echo 'Updating LSWS'
bash bin/webadmin.sh --upgrade 2>&1 /dev/null
echo 'Enabling OWASP'
bash bin/webadmin.sh --mod-secure enable
curl -sIk http://localhost:80/phpinfo.php | awk '/HTTP/ && /403/'
if [ ${?} = 0 ]; then
echo '[O] OWASP enable'
else
echo '[X] OWASP enable'
curl -sIk http://localhost:80/phpinfo.php | awk '/HTTP/ && /403/'
exit 1
fi
bash bin/webadmin.sh --mod-secure disable
curl -sIk http://localhost:80/phpinfo.php | grep -i WordPress
if [ ${?} = 0 ]; then
echo '[O] OWASP disable'
else
echo '[X] OWASP disable'
curl -sIk http://localhost:80/phpinfo.php
exit 1
fi
}
main(){
verify_lsws
verify_phpadmin
install_demo
verify_page
verify_owasp
verify_add_vh_wp
verify_del_vh_wp
}
main
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 - 2020 Litespeedtech
Copyright (c) 2019 - 2022 Litespeedtech
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+205 -70
View File
@@ -1,47 +1,60 @@
# OpenLiteSpeed WordPress Docker Container
[![Build Status](https://travis-ci.com/litespeedtech/ols-docker-env.svg?branch=master)](https://hub.docker.com/r/litespeedtech/openlitespeed)
![ols-docker-env](https://socialify.git.ci/litespeedtech/ols-docker-env/image?custom_language=Shell&description=1&font=Inter&forks=1&issues=1&language=1&logo=https%3A%2F%2Fwww.litespeedtech.com%2Fimages%2Flogos%2Flitespeed%2Flitespeed-logo-square.svg&name=1&owner=1&pattern=Plus&pulls=1&stargazers=1&theme=Auto)
[![Build Status](https://github.com/litespeedtech/ols-docker-env/workflows/docker-build/badge.svg)](https://github.com/litespeedtech/ols-docker-env/actions/)
[![docker pulls](https://img.shields.io/docker/pulls/litespeedtech/openlitespeed?style=flat&color=blue)](https://hub.docker.com/r/litespeedtech/openlitespeed)
[<img src="https://img.shields.io/badge/slack-LiteSpeed-blue.svg?logo=slack">](litespeedtech.com/slack)
[<img src="https://img.shields.io/twitter/follow/litespeedtech.svg?label=Follow&style=social">](https://twitter.com/litespeedtech)
[![LiteSpeed on Slack](https://img.shields.io/badge/slack-LiteSpeed-blue.svg?logo=slack)](https://litespeedtech.com/slack)
[![Follow on Twitter](https://img.shields.io/twitter/follow/litespeedtech.svg?label=Follow&style=social)](https://twitter.com/litespeedtech)
Install a lightweight WordPress container with OpenLiteSpeed Edge or Stable version based on Ubuntu 18.04 Linux.
Install a lightweight WordPress container with OpenLiteSpeed Edge or Stable version based on Ubuntu 24.04 Linux.
## Prerequisites
### Prerequisites
1. [Install Docker](https://www.docker.com/)
2. [Install Docker Compose](https://docs.docker.com/compose/)
## Configuration
Edit the `.env` file to update the demo site domain, default MySQL user, and password.
Feel free to check [Docker hub Tag page](https://hub.docker.com/repository/docker/litespeedtech/openlitespeed/tags) if you want to update default openlitespeed and php versions.
Feel free to check [Docker hub Tag page](https://hub.docker.com/repository/docker/litespeedtech/openlitespeed/tags) if you want to update default openlitespeed and php versions.
## Installation
Clone this repository or copy the files from this repository into a new folder:
```
```bash
git clone https://github.com/litespeedtech/ols-docker-env.git
```
Open a terminal, `cd` to the folder in which `docker-compose.yml` is saved, and run:
```
docker-compose up
Open a terminal, `cd` to the folder in which `docker compose.yml` is saved, and run:
```bash
docker compose up
```
Note: If you wish to run a single web server container, please see the [usage method here](https://github.com/litespeedtech/ols-dockerfiles#usage).
## Components
The docker image installs the following packages on your system:
|Component|Version|
| :-------------: | :-------------: |
|Linux|Ubuntu 18.04|
|OpenLiteSpeed|[Latest version](https://openlitespeed.org/downloads/)|
|MariaDB|[Stable version: 10.3](https://hub.docker.com/_/mariadb)|
|Linux|Ubuntu 24.04|
|OpenLiteSpeed|[Latest version](https://hub.docker.com/r/litespeedtech/openlitespeed)|
|MariaDB|[Latest Stable version: 11.8 LTS](https://hub.docker.com/_/mariadb)|
|PHP|[Latest version](http://rpms.litespeedtech.com/debian/)|
|LiteSpeed Cache|[Latest from WordPress.org](https://wordpress.org/plugins/litespeed-cache/)|
|ACME|[Latest from ACME official](https://github.com/acmesh-official/get.acme.sh)|
|WordPress|[Latest from WordPress](https://wordpress.org/download/)|
|phpMyAdmin|[Latest from dockerhub](https://hub.docker.com/r/bitnami/phpmyadmin/)|
|phpMyAdmin|[Latest from dockerhub](https://hub.docker.com/r/phpmyadmin/phpmyadmin/)|
|Redis|[Latest from dockerhub](https://hub.docker.com/_/redis/)|
## Data Structure
Cloned project
Cloned project
```bash
├── acme
├── bin
@@ -63,127 +76,249 @@ Cloned project
└── docker-compose.yml
```
* `acme` contains all applied certificates from Lets Encrypt
* `acme` contains all applied certificates from Lets Encrypt
* `bin` contains multiple CLI scripts to allow you add or delete virtual hosts, install applications, upgrade, etc
* `bin` contains multiple CLI scripts to allow you add or delete virtual hosts, install applications, upgrade, etc
* `data` stores the MySQL database
* `data` stores the MySQL database
* `logs` contains all of the web server logs and virtual host access logs
* `logs` contains all of the web server logs and virtual host access logs
* `lsws` contains all web server configuration files
* `lsws` contains all web server configuration files
* `sites` contains the document roots (the WordPress application will install here)
* `sites` contains the document roots (the WordPress application will install here)
## Usage
### Starting a Container
Start the container with the `up` or `start` methods:
```bash
docker compose up
```
docker-compose up
```
You can run with daemon mode, like so:
```bash
docker compose up -d
```
docker-compose up -d
```
The container is now built and running.
The container is now built and running.
### Stopping a Container
```bash
docker compose stop
```
docker-compose stop
```
### Removing Containers
To stop and remove all containers, use the `down` command:
```bash
docker compose down
```
docker-compose down
```
### Setting the WebAdmin Password
We strongly recommend you set your personal password right away.
```
```bash
bash bin/webadmin.sh my_password
```
### Starting a Demo Site
After running the following command, you should be able to access the WordPress installation with the configured domain. By default the domain is http://localhost.
```
After running the following command, you should be able to access the WordPress installation with the configured domain. By default the domain is <http://localhost>.
```bash
bash bin/demosite.sh
```
### Creating a Domain and Virtual Host
```
```bash
bash bin/domain.sh [-A, --add] example.com
```
> Please ignore SSL certificate warnings from the server. They happen if you haven't applied the certificate.
>
### Deleting a Domain and Virtual Host
```
```bash
bash bin/domain.sh [-D, --del] example.com
```
### Creating a Database
You can either automatically generate the user, password, and database names, or specify them. Use the following to auto generate:
```
```bash
bash bin/database.sh [-D, --domain] example.com
```
Use this command to specify your own names, substituting `user_name`, `my_password`, and `database_name` with your preferred values:
```
```bash
bash bin/database.sh [-D, --domain] example.com [-U, --user] USER_NAME [-P, --password] MY_PASS [-DB, --database] DATABASE_NAME
```
### Installing a WordPress Site
To preconfigure the `wp-config` file, run the `database.sh` script for your domain, before you use the following command to install WordPress:
```bash
bash bin/appinstall.sh [-A, --app] wordpress [-D, --domain] example.com
```
./bin/appinstall.sh [-A, --app] wordpress [-D, --domain] example.com
```
### Install ACME
We need to run the ACME installation command the **first time only**.
### Connecting to Redis
Go to [WordPress > LSCache Plugin > Cache > Object](https://docs.litespeedtech.com/lscache/lscwp/cache/#object-tab), select **Redis** method and input `redis` to the Host field.
### Install ACME
We need to run the ACME installation command the **first time only**.
With email notification:
```bash
bash bin/acme.sh [-I, --install] [-E, --email] EMAIL_ADDR
```
./bin/acme.sh [-I, --install] [-E, --email] EMAIL_ADDR
```
Without email notification:
```
./bin/acme.sh [-I, --install] [-NE, --no-email]
```
### Applying a Let's Encrypt Certificate
Use the root domain in this command, and it will check for a certificate and automatically apply one with and without `www`:
```bash
bash bin/acme.sh [-D, --domain] example.com
```
./bin/acme.sh [-D, --domain] example.com
Other parameters:
* [`-r`, `--renew`]: Renew a specific domain with -D or --domain parameter if posibile. To force renew, use -f parameter.
* [`-R`, `--renew-all`]: Renew all domains if possible. To force renew, use -f parameter.
* [`-f`, `-F`, `--force`]: Force renew for a specific domain or all domains.
* [`-v`, `--revoke`]: Revoke a domain.
* [`-V`, `--remove`]: Remove a domain.
### Using mkcert for Local Development SSL
For local development domains (`.test`, `.local`, `.dev`, etc.), you can use `mkcert` to generate trusted SSL certificates without warnings.
#### Installing mkcert
First-time installation (Windows with Chocolatey):
```bash
bash bin/mkcert.sh --install
```
This will:
* Install `mkcert` via Chocolatey
* Create and install a local Certificate Authority (CA) in your system trust store
#### Generating Local SSL Certificate
After adding a domain to your environment, generate an SSL certificate:
```bash
bash bin/mkcert.sh [-D, --domain] example.test
```
This will:
1. Check if the domain exists in your configuration
2. Generate certificates for `example.test` and `www.example.test`
3. Create a `dockerLocal` template with SSL configuration
4. Copy certificates to the container
5. Move the domain from the standard template to the SSL-enabled template
6. Restart OpenLiteSpeed
Your domain will now be accessible via HTTPS with a trusted certificate at `https://example.test`
#### Removing Local SSL Certificate
To remove the SSL certificate and revert to HTTP:
```bash
bash bin/mkcert.sh [-R, --remove] [-D, --domain] example.test
```
This will:
1. Remove the domain from the `dockerLocal` template
2. Move it back to the standard `docker` template
3. Delete certificate files from both host and container
4. Clean up empty templates if no other domains use SSL
5. Restart OpenLiteSpeed
> **Important**: You must add the domain to your environment first using `bash bin/domain.sh --add example.test` before generating certificates.
### Update Web Server
To upgrade the web server to latest stable version, run the following:
```
```bash
bash bin/webadmin.sh [-U, --upgrade]
```
### Apply OWASP ModSecurity
Enable OWASP `mod_secure` on the web server:
```
Enable OWASP `mod_secure` on the web server:
```bash
bash bin/webadmin.sh [-M, --mod-secure] enable
```
Disable OWASP `mod_secure` on the web server:
```
Disable OWASP `mod_secure` on the web server:
```bash
bash bin/webadmin.sh [-M, --mod-secure] disable
```
>Please ignore ModSecurity warnings from the server. They happen if some of the rules are not supported by the server.
>
### Accessing the Database
After installation, you can use phpMyAdmin to access the database by visiting `http://127.0.0.1:8080` or `https://127.0.0.1:8443`. The default username is `root`, and the password is the same as the one you supplied in the `.env` file.
## Customization
If you want to customize the image by adding some packages, e.g. `lsphp74-pspell`, just extend it with a Dockerfile.
1. We can create a `custom` folder and a `custom/Dockerfile` file under the main project.
If you want to customize the image by adding some packages, e.g. `lsphp83-pspell`, just extend it with a Dockerfile.
1. We can create a `custom` folder and a `custom/Dockerfile` file under the main project.
2. Add the following example code to `Dockerfile` under the custom folder
```
FROM litespeedtech/openlitespeed:latest
RUN apt-get update && apt-get install lsphp74-pspell -y
```
3. Add `build: ./custom` line under the "image: litespeedtech" of docker-composefile. So it will looks like this
```
litespeed:
image: litespeedtech/openlitespeed:${OLS_VERSION}-${PHP_VERSION}
build: ./custom
```
```bash
FROM litespeedtech/openlitespeed:latest
RUN apt-get update && apt-get install lsphp83-pspell -y
```
3. Add `build: ./custom` line under the "image: litespeedtech" of docker-composefile. So it will looks like this
```bash
litespeed:
image: litespeedtech/openlitespeed:${OLS_VERSION}-${PHP_VERSION}
build: ./custom
```
4. Build and start it with command:
```
docker-compose up --build
```
```bash
docker compose up --build
```
## Support & Feedback
If you still have a question after using OpenLiteSpeed Docker, you have a few options.
* Join [the GoLiteSpeed Slack community](litespeedtech.com/slack) for real-time discussion
* Join [the GoLiteSpeed Slack community](https://litespeedtech.com/slack) for real-time discussion
* Post to [the OpenLiteSpeed Forums](https://forum.openlitespeed.org/) for community support
* Reporting any issue on [Github ols-docker-env](https://github.com/litespeedtech/ols-docker-env/issues) project
**Pull requests are always welcome**
**_Pull requests are always welcome!_**
+114 -25
View File
@@ -8,6 +8,11 @@ TYPE=0
CONT_NAME='litespeed'
ACME_SRC='https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh'
EPACE=' '
RENEW=''
RENEW_ALL=''
FORCE=''
REVOKE=''
REMOVE=''
echow(){
FLAG=${1}
@@ -30,9 +35,17 @@ help_message(){
echo "${EPACE}${EPACE}Display help and exit."
echo -e "\033[1m Only for the First time\033[0m"
echow '--install --email [EMAIL_ADDR]'
echo "${EPACE}${EPACE}Will install ACME with the Email provided"
echow '--install --no-email'
echo "${EPACE}${EPACE}Will install ACME without the Email."
echo "${EPACE}${EPACE}Will install ACME with the Email provided"
echow '-r, --renew'
echo "${EPACE}${EPACE}Renew a specific domain with -D or --domain parameter if posibile. To force renew, use -f parameter."
echow '-R, --renew-all'
echo "${EPACE}${EPACE}Renew all domains if possible. To force renew, use -f parameter."
echow '-f, -F, --force'
echo "${EPACE}${EPACE}Force renew for a specific domain or all domains."
echow '-v, --revoke'
echo "${EPACE}${EPACE}Revoke a domain."
echow '-V, --remove'
echo "${EPACE}${EPACE}Remove a domain."
exit 0
;;
"3")
@@ -63,18 +76,22 @@ domain_filter(){
}
email_filter(){
local EMAIL_CLEAN="${1%\"}"
EMAIL_CLEAN="${EMAIL_CLEAN#\"}"
CKREG="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"
if [[ "${1}" =~ ${CKREG} ]] ; then
echo -e "[O] The E-mail \033[32m${1}\033[0m is valid."
if [[ "${EMAIL_CLEAN}" =~ ${CKREG} ]]; then
echo -e "[O] The E-mail \033[32m${EMAIL_CLEAN}\033[0m is valid."
else
echo -e "[X] The E-mail \e[31m${1}\e[39m is invalid"
echo -e "[X] The E-mail \e[31m${EMAIL_CLEAN}\e[39m is invalid"
exit 1
fi
}
cert_hook(){
echo '[Start] Adding ACME hook'
docker-compose exec ${CONT_NAME} su -s /bin/bash -c "certhookctl.sh"
docker compose exec ${CONT_NAME} su -s /bin/bash -c "certhookctl.sh"
echo '[End] Adding ACME hook'
}
@@ -109,14 +126,24 @@ domain_verify(){
install_acme(){
echo '[Start] Install ACME'
if [ "${1}" = 'true' ]; then
docker-compose exec litespeed su -c "cd; wget ${ACME_SRC}; chmod 755 acme.sh; \
./acme.sh --install --cert-home ~/.acme.sh/certs; \
rm ~/acme.sh"
docker compose exec litespeed su -c "
cd &&
wget ${ACME_SRC} &&
chmod 755 acme.sh &&
./acme.sh --install --cert-home ~/.acme.sh/certs &&
/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt &&
rm ~/acme.sh
"
elif [ "${2}" != '' ]; then
email_filter "${2}"
docker-compose exec litespeed su -c "cd; wget ${ACME_SRC}; chmod 755 acme.sh; \
./acme.sh --install --cert-home ~/.acme.sh/certs --accountemail ${2}; \
rm ~/acme.sh"
email_filter \"${2}\"
docker compose exec litespeed su -c "
cd &&
wget ${ACME_SRC} &&
chmod 755 acme.sh &&
./acme.sh --install --cert-home ~/.acme.sh/certs --accountemail ${2} &&
/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt &&
rm ~/acme.sh
"
else
help_message 1
exit 1
@@ -126,14 +153,14 @@ install_acme(){
uninstall_acme(){
echo '[Start] Uninstall ACME'
docker-compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --uninstall"
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --uninstall"
echo '[End] Uninstall ACME'
exit 0
}
check_acme(){
echo '[Start] Checking ACME'
docker-compose exec ${CONT_NAME} su -c "test -f /root/.acme.sh/acme.sh"
docker compose exec ${CONT_NAME} su -c "test -f /root/.acme.sh/acme.sh"
if [ ${?} != 0 ]; then
install_acme "${NO_EMAIL}" "${EMAIL}"
cert_hook
@@ -143,7 +170,7 @@ check_acme(){
}
lsws_restart(){
docker-compose exec ${CONT_NAME} su -c '/usr/local/lsws/bin/lswsctrl restart >/dev/null'
docker compose exec ${CONT_NAME} su -c '/usr/local/lsws/bin/lswsctrl restart >/dev/null'
}
doc_root_verify(){
@@ -152,7 +179,7 @@ doc_root_verify(){
else
DOC_PATH="${DOC_ROOT}"
fi
docker-compose exec ${CONT_NAME} su -c "[ -e ${DOC_PATH} ]"
docker compose exec ${CONT_NAME} su -c "[ -e ${DOC_PATH} ]"
if [ ${?} -eq 0 ]; then
echo -e "[O] The document root folder \033[32m${DOC_PATH}\033[0m does exist."
else
@@ -164,9 +191,9 @@ doc_root_verify(){
install_cert(){
echo '[Start] Apply Lets Encrypt Certificate'
if [ ${TYPE} = 1 ]; then
docker-compose exec ${CONT_NAME} su -c "/root/.acme.sh/acme.sh --issue -d ${1} -w ${DOC_PATH}"
docker compose exec ${CONT_NAME} su -c "/root/.acme.sh/acme.sh --issue -d ${1} -w ${DOC_PATH}"
elif [ ${TYPE} = 2 ]; then
docker-compose exec ${CONT_NAME} su -c "/root/.acme.sh/acme.sh --issue -d ${1} -d www.${1} -w ${DOC_PATH}"
docker compose exec ${CONT_NAME} su -c "/root/.acme.sh/acme.sh --issue -d ${1} -d www.${1} -w ${DOC_PATH}"
else
echo 'unknown Type!'
exit 2
@@ -174,7 +201,57 @@ install_cert(){
echo '[End] Apply Lets Encrypt Certificate'
}
renew_acme(){
echo '[Start] Renew ACME'
if [ "${FORCE}" = 'true' ]; then
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --renew --domain ${1} --force"
else
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --renew --domain ${1}"
fi
echo '[End] Renew ACME'
lsws_restart
}
renew_all_acme(){
echo '[Start] Renew all ACME'
if [ "${FORCE}" = 'true' ]; then
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --renew-all --force"
else
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --renew-all"
fi
echo '[End] Renew all ACME'
lsws_restart
}
revoke(){
echo '[Start] Revoke a domain'
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --revoke --domain ${1}"
echo '[End] Revoke a domain'
lsws_restart
}
remove(){
echo '[Start] Remove a domain'
docker compose exec ${CONT_NAME} su -c "~/.acme.sh/acme.sh --remove --domain ${1}"
echo '[End] Remove a domain'
lsws_restart
}
main(){
if [ "${RENEW_ALL}" = 'true' ]; then
renew_all_acme
exit 0
elif [ "${RENEW}" = 'true' ]; then
renew_acme ${DOMAIN}
exit 0
elif [ "${REVOKE}" = 'true' ]; then
revoke ${DOMAIN}
exit 0
elif [ "${REMOVE}" = 'true' ]; then
remove ${DOMAIN}
exit 0
fi
check_acme
domain_filter ${DOMAIN}
www_domain ${DOMAIN}
@@ -200,14 +277,26 @@ while [ ! -z "${1}" ]; do
-[uU] | --uninstall )
UNINSTALL=true
uninstall_acme
;;
;;
-[fF] | --force )
FORCE=true
;;
-[r] | --renew )
RENEW=true
;;
-[R] | --renew-all )
RENEW_ALL=true
;;
-[v] | --revoke )
REVOKE=true
;;
-[V] | --remove )
REMOVE=true
;;
-[eE] | --email ) shift
check_input "${1}"
EMAIL="${1}"
;;
-NE | --no-email ) shift
NO_EMAIL=true
;;
;;
*)
help_message 2
;;
+1 -1
View File
@@ -27,7 +27,7 @@ check_input(){
}
app_download(){
docker-compose exec litespeed su -c "appinstallctl.sh --app ${1} --domain ${2}"
docker compose exec litespeed su -c "appinstallctl.sh --app ${1} --domain ${2}"
bash bin/webadmin.sh -r
exit 0
}
+25 -399
View File
@@ -6,7 +6,7 @@ APP_NAME=''
DOMAIN=''
WWW_UID=''
WWW_GID=''
WP_CONST_CONF=''
WPCONSTCONF=''
PUB_IP=$(curl -s http://checkip.amazonaws.com)
DB_HOST='mysql'
PLUGINLIST="litespeed-cache.zip"
@@ -81,11 +81,11 @@ set_vh_docroot(){
if [ "${VHNAME}" != '' ]; then
VH_ROOT="${DEFAULT_VH_ROOT}/${VHNAME}"
VH_DOC_ROOT="${DEFAULT_VH_ROOT}/${VHNAME}/html"
WP_CONST_CONF="${VH_DOC_ROOT}/wp-content/plugins/litespeed-cache/data/const.default.ini"
WPCONSTCONF="${VH_DOC_ROOT}/wp-content/plugins/litespeed-cache/data/const.default.json"
elif [ -d ${DEFAULT_VH_ROOT}/${1}/html ]; then
VH_ROOT="${DEFAULT_VH_ROOT}/${1}"
VH_DOC_ROOT="${DEFAULT_VH_ROOT}/${1}/html"
WP_CONST_CONF="${VH_DOC_ROOT}/wp-content/plugins/litespeed-cache/data/const.default.ini"
WPCONSTCONF="${VH_DOC_ROOT}/wp-content/plugins/litespeed-cache/data/const.default.json"
else
echo "${DEFAULT_VH_ROOT}/${1}/html does not exist, please add domain first! Abort!"
exit 1
@@ -95,7 +95,7 @@ set_vh_docroot(){
check_sql_native(){
local COUNTER=0
local LIMIT_NUM=100
until [ "$(curl -v mysql:3306 2>&1 | grep native)" ]; do
until [ "$(curl -v mysql:3306 2>&1 | grep -i 'native\|Connected')" ]; do
echo "Counter: ${COUNTER}/${LIMIT_NUM}"
COUNTER=$((COUNTER+1))
if [ ${COUNTER} = 10 ]; then
@@ -148,402 +148,28 @@ get_theme_name(){
}
set_lscache(){
cat << EOM > "${WP_CONST_CONF}"
;
; This is the predefined default LSCWP configuration file
;
; All the keys and values please refer \`src/const.cls.php\`
;
; Comments start with \`;\`
;
;; -------------------------------------------------- ;;
;; -------------- General ----------------- ;;
;; -------------------------------------------------- ;;
; O_AUTO_UPGRADE
auto_upgrade = false
; O_API_KEY
api_key = ''
; O_SERVER_IP
server_ip = ''
; O_NEWS
news = false
;; -------------------------------------------------- ;;
;; -------------- Cache ----------------- ;;
;; -------------------------------------------------- ;;
cache-priv = true
cache-commenter = true
cache-rest = true
cache-page_login = true
cache-favicon = true
cache-resources = true
cache-browser = false
cache-mobile = false
cache-mobile_rules = 'Mobile
Android
Silk/
Kindle
BlackBerry
Opera Mini
Opera Mobi'
cache-exc_useragents = ''
cache-exc_cookies = ''
cache-exc_qs = ''
cache-exc_cat = ''
cache-exc_tag = ''
cache-force_uri = ''
cache-force_pub_uri = ''
cache-priv_uri = ''
cache-exc = ''
cache-exc_roles = ''
cache-drop_qs = 'fbclid
gclid
utm*
_ga'
cache-ttl_pub = 604800
cache-ttl_priv = 1800
cache-ttl_frontpage = 604800
cache-ttl_feed = 604800
; O_CACHE_TTL_REST
cache-ttl_rest = 604800
cache-ttl_browser = 31557600
cache-login_cookie = ''
cache-vary_group = ''
cache-ttl_status = '403 3600
404 3600
500 3600'
;; -------------------------------------------------- ;;
;; -------------- Purge ----------------- ;;
;; -------------------------------------------------- ;;
; O_PURGE_ON_UPGRADE
purge-upgrade = true
; O_PURGE_STALE
purge-stale = true
purge-post_all = false
purge-post_f = true
purge-post_h = true
purge-post_p = true
purge-post_pwrp = true
purge-post_a = true
purge-post_y = false
purge-post_m = true
purge-post_d = false
purge-post_t = true
purge-post_pt = true
purge-timed_urls = ''
purge-timed_urls_time = ''
purge-hook_all = 'switch_theme
wp_create_nav_menu
wp_update_nav_menu
wp_delete_nav_menu
create_term
edit_terms
delete_term
add_link
edit_link
delete_link'
;; -------------------------------------------------- ;;
;; -------------- ESI ----------------- ;;
;; -------------------------------------------------- ;;
; O_ESI
esi = false
; O_ESI_CACHE_ADMBAR
esi-cache_admbar = true
; O_ESI_CACHE_COMMFORM
esi-cache_commform = true
; O_ESI_NONCE
esi-nonce = 'stats_nonce
subscribe_nonce'
;; -------------------------------------------------- ;;
;; -------------- Utilities ----------------- ;;
;; -------------------------------------------------- ;;
util-heartbeat = true
util-instant_click = false
util-check_advcache = true
util-no_https_vary = false
;; -------------------------------------------------- ;;
;; -------------- Debug ----------------- ;;
;; -------------------------------------------------- ;;
; O_DEBUG_DISABLE_ALL
debug-disable_all = false
; O_DEBUG
debug = false
; O_DEBUG_IPS
debug-ips = '127.0.0.1'
; O_DEBUG_LEVEL
debug-level = false
; O_DEBUG_FILESIZE
debug-filesize = 3
; O_DEBUG_COOKIE
debug-cookie = false
; O_DEBUG_COLLAPS_QS
debug-collaps_qs = false
; O_DEBUG_INC
debug-inc = ''
; O_DEBUG_EXC
debug-exc = ''
;; -------------------------------------------------- ;;
;; -------------- DB Optm ----------------- ;;
;; -------------------------------------------------- ;;
; O_DB_OPTM_REVISIONS_MAX
db_optm-revisions_max = 0
; O_DB_OPTM_REVISIONS_AGE
db_optm-revisions_age = 0
;; -------------------------------------------------- ;;
;; -------------- HTML Optm ----------------- ;;
;; -------------------------------------------------- ;;
; O_OPTM_CSS_MIN
optm-css_min = false
optm-css_inline_min = false
; O_OPTM_CSS_COMB
optm-css_comb = false
optm-css_comb_priority = false
; O_OPTM_CSS_HTTP2
optm-css_http2 = false
optm-css_exc = ''
; O_OPTM_JS_MIN
optm-js_min = false
optm-js_inline_min = false
; O_OPTM_JS_COMB
optm-js_comb = false
optm-js_comb_priority = false
; O_OPTM_JS_HTTP2
optm-js_http2 = false
; O_OPTM_EXC_JQ
optm-js_exc = ''
optm-ttl = 604800
optm-html_min = false
optm-qs_rm = false
optm-ggfonts_rm = false
; O_OPTM_CSS_ASYNC
optm-css_async = false
; O_OPTM_CCSS_GEN
optm-ccss_gen = true
; O_OPTM_CCSS_ASYNC
optm-ccss_async = true
; O_OPTM_CSS_ASYNC_INLINE
optm-css_async_inline = true
; O_OPTM_CSS_FONT_DISPLAY
optm-css_font_display = false
; O_OPTM_JS_DEFER
optm-js_defer = false
; O_OPTM_JS_INLINE_DEFER
optm-js_inline_defer = false
optm-emoji_rm = false
optm-exc_jq = true
optm-ggfonts_async = false
optm-max_size = 2
optm-rm_comment = false
optm-exc_roles = ''
optm-ccss_con = ''
optm-js_defer_exc = ''
; O_OPTM_DNS_PREFETCH
optm-dns_prefetch = ''
; O_OPTM_DNS_PREFETCH_CTRL
optm-dns_prefetch_ctrl = false
optm-exc = ''
; O_OPTM_CCSS_SEP_POSTTYPE
optm-ccss_sep_posttype = ''
; O_OPTM_CCSS_SEP_URI
optm-ccss_sep_uri = ''
;; -------------------------------------------------- ;;
;; -------------- Object Cache ----------------- ;;
;; -------------------------------------------------- ;;
object = true
object-kind = false
;object-host = 'localhost'
object-host = '/var/www/memcached.sock'
;object-port = 11211
cache_object_port = ''
object-life = 360
object-persistent = true
object-admin = true
object-transients = true
object-db_id = 0
object-user = ''
object-pswd = ''
object-global_groups = 'users
userlogins
usermeta
user_meta
site-transient
site-options
site-lookup
blog-lookup
blog-details
rss
global-posts
blog-id-cache'
object-non_persistent_groups = 'comment
counts
plugins
wc_session_id'
;; -------------------------------------------------- ;;
;; -------------- Discussion ----------------- ;;
;; -------------------------------------------------- ;;
; O_DISCUSS_AVATAR_CACHE
discuss-avatar_cache = false
; O_DISCUSS_AVATAR_CRON
discuss-avatar_cron = false
; O_DISCUSS_AVATAR_CACHE_TTL
discuss-avatar_cache_ttl = 604800
;; -------------------------------------------------- ;;
;; -------------- Media ----------------- ;;
;; -------------------------------------------------- ;;
; O_MEDIA_LAZY
media-lazy = false
; O_MEDIA_LAZY_PLACEHOLDER
media-lazy_placeholder = ''
; O_MEDIA_PLACEHOLDER_RESP
media-placeholder_resp = false
; O_MEDIA_PLACEHOLDER_RESP_COLOR
media-placeholder_resp_color = '#cfd4db'
; O_MEDIA_PLACEHOLDER_RESP_GENERATOR
media-placeholder_resp_generator = false
; O_MEDIA_PLACEHOLDER_RESP_SVG
media-placeholder_resp_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}"><rect width="100%" height="100%" fill="{color}"/></svg>'
; O_MEDIA_PLACEHOLDER_LQIP
media-placeholder_lqip = false
; O_MEDIA_PLACEHOLDER_LQIP_QUAL
media-placeholder_lqip_qual = 4
; O_MEDIA_PLACEHOLDER_RESP_ASYNC
media-placeholder_resp_async = true
; O_MEDIA_IFRAME_LAZY
media-iframe_lazy = false
; O_MEDIA_LAZYJS_INLINE
media-lazyjs_inline = false
; O_MEDIA_LAZY_EXC
media-lazy_exc = ''
; O_MEDIA_LAZY_CLS_EXC
media-lazy_cls_exc = ''
; O_MEDIA_LAZY_PARENT_CLS_EXC
media-lazy_parent_cls_exc = ''
; O_MEDIA_IFRAME_LAZY_CLS_EXC
media-iframe_lazy_cls_exc = ''
; O_MEDIA_IFRAME_LAZY_PARENT_CLS_EXC
media-iframe_lazy_parent_cls_exc = ''
; O_MEDIA_LAZY_URI_EXC
media-lazy_uri_exc = ''
;; -------------------------------------------------- ;;
;; -------------- Image Optm ----------------- ;;
;; -------------------------------------------------- ;;
img_optm-auto = false
img_optm-cron = true
img_optm-ori = true
img_optm-rm_bkup = false
img_optm-webp = false
img_optm-lossless = false
img_optm-exif = false
img_optm-webp_replace = false
img_optm-webp_attr = 'img.src
div.data-thumb
img.data-src
div.data-large_image
img.retina_logo_url
div.data-parallax-image
video.poster'
img_optm-webp_replace_srcset = false
img_optm-jpg_quality = 82
;; -------------------------------------------------- ;;
;; -------------- Crawler ----------------- ;;
;; -------------------------------------------------- ;;
crawler = false
crawler-inc_posts = true
crawler-inc_pages = true
crawler-inc_cats = true
crawler-inc_tags = true
crawler-exc_cpt = ''
crawler-order_links = 'date_desc'
crawler-usleep = 500
crawler-run_duration = 400
crawler-run_interval = 600
crawler-crawl_interval = 302400
crawler-threads = 3
crawler-timeout = 30
crawler-load_limit = 1
; O_CRAWLER_SITEMAP
crawler-sitemap = ''
; O_CRAWLER_DROP_DOMAIN
crawler-drop_domain = true
crawler-roles = ''
crawler-cookies = ''
;; -------------------------------------------------- ;;
;; -------------- Misc ----------------- ;;
;; -------------------------------------------------- ;;
; O_MISC_HTACCESS_FRONT
misc-htaccess_front = ''
; O_MISC_HTACCESS_BACK
misc-htaccess_back = ''
; O_MISC_HEARTBEAT_FRONT
misc-heartbeat_front = false
; O_MISC_HEARTBEAT_FRONT_TTL
misc-heartbeat_front_ttl = 60
; O_MISC_HEARTBEAT_BACK
misc-heartbeat_back = false
; O_MISC_HEARTBEAT_BACK_TTL
misc-heartbeat_back_ttl = 60
; O_MISC_HEARTBEAT_EDITOR
misc-heartbeat_editor = false
; O_MISC_HEARTBEAT_EDITOR_TTL
misc-heartbeat_editor_ttl = 15
;; -------------------------------------------------- ;;
;; -------------- CDN ----------------- ;;
;; -------------------------------------------------- ;;
cdn = false
cdn-ori = ''
cdn-ori_dir = ''
cdn-exc = ''
cdn-remote_jq = false
cdn-quic = false
cdn-quic_email = ''
cdn-quic_key = ''
cdn-cloudflare = false
cdn-cloudflare_email = ''
cdn-cloudflare_key = ''
cdn-cloudflare_name = ''
cdn-cloudflare_zone = ''
; \`cdn-mapping\` needs to be put in the end with a section tag
;; -------------------------------------------------- ;;
;; -------------- CDN 2 ----------------- ;;
;; -------------------------------------------------- ;;
; <------------ CDN Mapping Example BEGIN -------------------->
; Need to keep the section tag \`[cdn-mapping]\` before list.
;
; NOTE 1) Need to set all child options to make all resources to be replaced without missing.
; NOTE 2) \`url[n]\` option must have to enable the row setting of \`n\`.
; NOTE 3) This section needs to be put in the end of this .ini file
;
; To enable the 2nd mapping record by default, please remove the \`;;\` in the related lines.
[cdn-mapping]
url[0] = ''
inc_js[0] = true
inc_css[0] = true
inc_img[0] = true
filetype[0] = '.aac
.css
.eot
.gif
.jpeg
.js
.jpg
.less
.mp3
.mp4
.ogg
.otf
.pdf
.png
.svg
.ttf
.woff'
;;url[1] = 'https://2nd_CDN_url.com/'
;;filetype[1] = '.webm'
; <------------ CDN Mapping Example END ------------------>
EOM
if [ ! -f ${VH_DOC_ROOT}/wp-content/themes/${THEME}/functions.php.bk ]; then
cp ${VH_DOC_ROOT}/wp-content/themes/${THEME}/functions.php ${VH_DOC_ROOT}/wp-content/themes/${THEME}/functions.php.bk
wget -q -O ${WPCONSTCONF} https://raw.githubusercontent.com/litespeedtech/lscache_wp/refs/heads/master/data/const.default.json
if [ -f ${WPCONSTCONF} ]; then
sed -ie 's/"object": .*"/"object": '\"true\"'/g' ${WPCONSTCONF}
sed -ie 's/"object-kind": .*"/"object-kind": '\"true\"'/g' ${WPCONSTCONF}
sed -ie 's/"object-host": .*"/"object-host": '\"redis\"'/g' ${WPCONSTCONF}
sed -ie 's/"object-port": .*"/"object-port": '\"6379\"'/g' ${WPCONSTCONF}
fi
THEME_PATH="${VH_DOC_ROOT}/wp-content/themes/${THEME}"
if [ ! -f ${THEME_PATH}/functions.php ]; then
cat >> "${THEME_PATH}/functions.php" <<END
<?php
require_once( WP_CONTENT_DIR.'/../wp-admin/includes/plugin.php' );
\$path = 'litespeed-cache/litespeed-cache.php' ;
if (!is_plugin_active( \$path )) {
activate_plugin( \$path ) ;
rename( __FILE__ . '.bk', __FILE__ );
}
END
elif [ ! -f ${THEME_PATH}/functions.php.bk ]; then
cp ${THEME_PATH}/functions.php ${THEME_PATH}/functions.php.bk
ck_ed
ed ${VH_DOC_ROOT}/wp-content/themes/${THEME}/functions.php << END >>/dev/null 2>&1
ed ${THEME_PATH}/functions.php << END >>/dev/null 2>&1
2i
require_once( WP_CONTENT_DIR.'/../wp-admin/includes/plugin.php' );
\$path = 'litespeed-cache/litespeed-cache.php' ;
+8 -8
View File
@@ -94,16 +94,16 @@ add_domain(){
if [ "${CK_RESULT}" != '' ]; then
echo "# It appears the domain already exist! Check the ${LS_HTTPD_CONF} if you believe this is a mistake!"
exit 1
fi
fi
add_ls_domain
elif [ "${LSV}" = 'openlitespeed' ]; then
check_duplicate "member.*${DOMAIN}" ${OLS_HTTPD_CONF}
if [ "${CK_RESULT}" != '' ]; then
echo "# It appears the domain already exist! Check the ${OLS_HTTPD_CONF} if you believe this is a mistake!"
exit 1
fi
fi
add_ls_domain
add_ols_domain
fi
add_ols_domain
fi
}
del_ls_domain(){
@@ -129,15 +129,15 @@ del_domain(){
echo "# Domain non-exist! Check the ${LS_HTTPD_CONF} if you believe this is a mistake!"
exit 1
fi
del_ls_domain ${1}
elif [ "${LSV}" = 'openlitespeed' ]; then
check_duplicate "member.*${DOMAIN}" ${OLS_HTTPD_CONF}
if [ "${CK_RESULT}" = '' ]; then
echo "# Domain non-exist! Check the ${OLS_HTTPD_CONF} if you believe this is a mistake!"
exit 1
fi
fi
del_ols_domain ${1}
fi
del_ls_domain ${1}
del_ols_domain ${1}
}
check_input ${1}
+42 -54
View File
@@ -1,10 +1,12 @@
#!/bin/bash
LSDIR='/usr/local/lsws'
OWASP_DIR="${LSDIR}/conf/owasp"
CRS_DIR='owasp-modsecurity-crs'
RULE_FILE='modsec_includes.conf'
LS_HTTPD_CONF="${LSDIR}/conf/httpd_config.xml"
OLS_HTTPD_CONF="${LSDIR}/conf/httpd_config.conf"
EPACE=' '
OWASP_V='4.3.0'
echow(){
FLAG=${1}
@@ -89,7 +91,7 @@ enable_ls_modsec(){
<censorshipRuleSet>\n\
<name>ModSec</name>\n\
<enabled>1</enabled>\n\
<ruleSet>include ${OWASP_DIR}/modsec_includes.conf</ruleSet>\n\
<ruleSet>include ${OWASP_DIR}/${RULE_FILE}</ruleSet>\n\
</censorshipRuleSet>=" ${LS_HTTPD_CONF}
fi
}
@@ -137,74 +139,60 @@ disable_modsec(){
fi
}
install_git(){
if [ ! -f /usr/bin/git ]; then
echo 'Install git'
apt-get install git -y >/dev/null 2>&1
install_unzip(){
if [ ! -f /usr/bin/unzip ]; then
echo 'Install Unzip'
apt update >/dev/null 2>&1
apt-get install unzip -y >/dev/null 2>&1
fi
}
backup_owasp(){
if [ -d ${OWASP_DIR} ]; then
echo "Detect ${OWASP_DIR} folder exist, move to ${OWASP_DIR}.$(date +%F).bk"
if [ -d ${OWASP_DIR}.$(date +%F).bk ]; then
rm -rf ${OWASP_DIR}.$(date +%F).bk
fi
mv ${OWASP_DIR} ${OWASP_DIR}.$(date +%F).bk
fi
}
install_owasp(){
cd ${OWASP_DIR}
echo 'Download OWASP rules'
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git >/dev/null 2>&1
wget -q https://github.com/coreruleset/coreruleset/archive/refs/tags/v${OWASP_V}.zip
unzip -qq v${OWASP_V}.zip
rm -f v${OWASP_V}.zip
mv coreruleset-* ${CRS_DIR}
}
configure_owasp(){
echo 'Config OWASP rules.'
cd ${OWASP_DIR}
echo "include modsecurity.conf
include owasp-modsecurity-crs/crs-setup.conf
include owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
include owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9003-NEXTCLOUD-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9004-DOKUWIKI-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9005-CPANEL-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-903.9006-XENFORO-EXCLUSION-RULES.conf
include owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
include owasp-modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf
include owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
include owasp-modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf
include owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf
include owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
include owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf
include owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
include owasp-modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
include owasp-modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
include owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf
include owasp-modsecurity-crs/rules/REQUEST-934-APPLICATION-ATTACK-NODEJS.conf
include owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
include owasp-modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
include owasp-modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
include owasp-modsecurity-crs/rules/REQUEST-944-APPLICATION-ATTACK-JAVA.conf
include owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf
include owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf
include owasp-modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
include owasp-modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
include owasp-modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
include owasp-modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
include owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
include owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf
include owasp-modsecurity-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf">modsec_includes.conf
echo "SecRuleEngine On">modsecurity.conf
cd ${OWASP_DIR}/owasp-modsecurity-crs
if [ -f crs-setup.conf.example ]; then
mv crs-setup.conf.example crs-setup.conf
if [ -f ${CRS_DIR}/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example ]; then
mv ${CRS_DIR}/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example ${CRS_DIR}/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
fi
if [ -f ${CRS_DIR}/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example ]; then
mv ${CRS_DIR}/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example ${CRS_DIR}/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
fi
if [ -f ${RULE_FILE} ]; then
mv ${RULE_FILE} ${RULE_FILE}.bk
fi
echo 'include modsecurity.conf' >> ${RULE_FILE}
if [ -f ${CRS_DIR}/crs-setup.conf.example ]; then
mv ${CRS_DIR}/crs-setup.conf.example ${CRS_DIR}/crs-setup.conf
echo "include ${CRS_DIR}/crs-setup.conf" >> ${RULE_FILE}
fi
cd ${OWASP_DIR}/owasp-modsecurity-crs/rules
if [ -f REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example ]; then
mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
fi
if [ -f RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example ]; then
mv RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
fi
ALL_RULES="$(ls ${CRS_DIR}/rules/ | grep 'REQUEST-\|RESPONSE-')"
echo "${ALL_RULES}" | while read LINE; do echo "include ${CRS_DIR}/rules/${LINE}" >> ${RULE_FILE}; done
echo 'SecRuleEngine On' > modsecurity.conf
chown -R lsadm ${OWASP_DIR}
}
main_owasp(){
backup_owasp
mk_owasp_dir
install_git
install_unzip
install_owasp
configure_owasp
check_lsv
@@ -228,4 +216,4 @@ while [ ! -z "${1}" ]; do
;;
esac
shift
done
done
+41 -6
View File
@@ -8,6 +8,7 @@ SQL_PASS=''
ANY="'%'"
SET_OK=0
EPACE=' '
METHOD=0
echow(){
FLAG=${1}
@@ -19,10 +20,13 @@ help_message(){
echo -e "\033[1mOPTIONS\033[0m"
echow '-D, --domain [DOMAIN_NAME]'
echo "${EPACE}${EPACE}Example: database.sh -D example.com"
echo "${EPACE}${EPACE}Will auto generate Database/username/password for the domain"
echo "${EPACE}${EPACE}Will auto-generate Database/username/password for the domain"
echow '-D, --domain [DOMAIN_NAME] -U, --user [xxx] -P, --password [xxx] -DB, --database [xxx]'
echo "${EPACE}${EPACE}Example: database.sh -D example.com -U USERNAME -P PASSWORD -DB DATABASENAME"
echo "${EPACE}${EPACE}Will create Database/username/password by given"
echow '-R, --delete -DB, --database [xxx] -U, --user [xxx]'
echo "${EPACE}${EPACE}Example: database.sh -r -DB DATABASENAME -U USERNAME"
echo "${EPACE}${EPACE}Will delete the database (require) and username (optional) by given"
echow '-H, --help'
echo "${EPACE}${EPACE}Display help and exit."
exit 0
@@ -79,7 +83,7 @@ EOT
}
check_db_access(){
docker-compose exec mysql su -c "mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e 'status'" >/dev/null 2>&1
docker compose exec -T mysql su -c "mariadb -uroot --password=${MYSQL_ROOT_PASSWORD} -e 'status'" >/dev/null 2>&1
if [ ${?} != 0 ]; then
echo '[X] DB access failed, please check!'
exit 1
@@ -87,21 +91,45 @@ check_db_access(){
}
check_db_exist(){
docker-compose exec mysql su -c "test -e /var/lib/mysql/${1}"
docker compose exec -T mysql su -c "test -e /var/lib/mysql/${1}"
if [ ${?} = 0 ]; then
echo "Database ${1} already exist, skip DB creation!"
exit 0
fi
}
check_db_not_exist(){
docker compose exec -T mysql su -c "test -e /var/lib/mysql/${1}"
if [ ${?} != 0 ]; then
echo "Database ${1} doesn't exist, skip DB deletion!"
exit 0
fi
}
db_setup(){
docker-compose exec mysql su -c 'mysql -uroot -p${MYSQL_ROOT_PASSWORD} \
docker compose exec -T mysql su -c 'mariadb -uroot --password=${MYSQL_ROOT_PASSWORD} \
-e "CREATE DATABASE '${SQL_DB}';" \
-e "GRANT ALL PRIVILEGES ON '${SQL_DB}'.* TO '${SQL_USER}'@'${ANY}' IDENTIFIED BY '${SQL_PASS}';" \
-e "FLUSH PRIVILEGES;"'
SET_OK=${?}
}
db_delete(){
if [ "${SQL_DB}" == '' ]; then
echo "Database parameter is required!"
exit 0
fi
if [ "${SQL_USER}" == '' ]; then
SQL_USER="${SQL_DB}"
fi
check_db_not_exist ${SQL_DB}
docker compose exec -T mysql su -c 'mariadb -uroot --password=${MYSQL_ROOT_PASSWORD} \
-e "DROP DATABASE IF EXISTS '${SQL_DB}';" \
-e "DROP USER IF EXISTS '${SQL_USER}'@'${ANY}';" \
-e "FLUSH PRIVILEGES;"'
echo "Database ${SQL_DB} and User ${SQL_USER} are deleted!"
}
auto_setup_main(){
check_input ${DOMAIN}
gen_pass
@@ -124,6 +152,10 @@ specify_setup_main(){
}
main(){
if [ ${METHOD} == 1 ]; then
db_delete
exit 0
fi
if [ "${SQL_USER}" != '' ] && [ "${SQL_PASS}" != '' ] && [ "${SQL_DB}" != '' ]; then
specify_setup_main
else
@@ -148,11 +180,14 @@ while [ ! -z "${1}" ]; do
;;
-db | -DB | -database| --database) shift
SQL_DB="${1}"
;;
;;
-[rR] | -del | --del | --delete)
METHOD=1
;;
*)
help_message
;;
esac
shift
done
main
main
+1 -1
View File
@@ -71,7 +71,7 @@ EOT
}
app_download(){
docker-compose exec ${CONT_NAME} su -c "appinstallctl.sh --app ${1} --domain ${2}"
docker compose exec -T ${CONT_NAME} su -c "appinstallctl.sh --app ${1} --domain ${2}"
}
lsws_restart(){
+2 -2
View File
@@ -27,7 +27,7 @@ check_input(){
add_domain(){
check_input ${1}
docker-compose exec ${CONT_NAME} su -s /bin/bash lsadm -c "cd /usr/local/lsws/conf && domainctl.sh --add ${1}"
docker compose exec ${CONT_NAME} su -s /bin/bash lsadm -c "cd /usr/local/lsws/conf && domainctl.sh --add ${1}"
if [ ! -d "./sites/${1}" ]; then
mkdir -p ./sites/${1}/{html,logs,certs}
fi
@@ -36,7 +36,7 @@ add_domain(){
del_domain(){
check_input ${1}
docker-compose exec ${CONT_NAME} su -s /bin/bash lsadm -c "cd /usr/local/lsws/conf && domainctl.sh --del ${1}"
docker compose exec ${CONT_NAME} su -s /bin/bash lsadm -c "cd /usr/local/lsws/conf && domainctl.sh --del ${1}"
bash bin/webadmin.sh -r
}
+463
View File
@@ -0,0 +1,463 @@
#!/usr/bin/env bash
DOMAIN=''
INSTALL=''
REMOVE=''
CONT_NAME='litespeed'
CERT_DIR='./certs'
EPACE=' '
echow(){
FLAG=${1}
shift
echo -e "\033[1m${EPACE}${FLAG}\033[0m${@}"
}
help_message(){
echo -e "\033[1mUSAGE\033[0m"
echo "${EPACE}mkcert.sh [OPTIONS]"
echo ""
echo -e "\033[1mOPTIONS\033[0m"
echow '-D, --domain [DOMAIN_NAME]'
echo "${EPACE}${EPACE}Example: mkcert.sh --domain example.test"
echo "${EPACE}${EPACE}Will create certificate for example.test and www.example.test"
echow '-I, --install'
echo "${EPACE}${EPACE}Install mkcert on Windows (requires Chocolatey)"
echow '-R, --remove'
echo "${EPACE}${EPACE}Remove certificate for a specific domain. Must be used with --domain."
echo "${EPACE}${EPACE}Example: mkcert.sh --remove --domain example.test"
echow '-H, --help'
echo "${EPACE}${EPACE}Display help and exit"
exit 0
}
check_input(){
if [ -z "${1}" ]; then
help_message
fi
}
domain_filter(){
if [ -z "${1}" ]; then
echo "[X] Domain name is required!"
exit 1
fi
DOMAIN="${1}"
DOMAIN="${DOMAIN#http://}"
DOMAIN="${DOMAIN#https://}"
DOMAIN="${DOMAIN#ftp://}"
DOMAIN="${DOMAIN%%/*}"
}
www_domain(){
CHECK_WWW=$(echo ${1} | cut -c1-4)
if [[ ${CHECK_WWW} == www. ]] ; then
DOMAIN=$(echo ${1} | cut -c 5-)
else
DOMAIN=${1}
fi
WWW_DOMAIN="www.${DOMAIN}"
}
check_mkcert() {
echo "[Start] Checking mkcert installation..."
if MKCERT_CMD=$(command -v mkcert.exe 2>/dev/null || command -v mkcert 2>/dev/null); then
echo "[✔] mkcert found at: ${MKCERT_CMD}"
else
echo "[✖] mkcert not found!"
echo "→ Please run 'bash bin/mkcert.sh --install' or install it manually."
echo " Windows: choco install mkcert"
echo " (Linux/macOS support can be added here later)"
exit 1
fi
echo "[End] mkcert check completed."
}
install_mkcert() {
echo "[Start] Installing mkcert..."
case "$(uname -s)" in
Linux*) OS="linux" ;;
Darwin*) OS="mac" ;;
MINGW*|MSYS*|CYGWIN*|Windows*) OS="windows" ;;
*) echo "[X] Unsupported OS: $(uname -s)"; exit 1 ;;
esac
echo "[*] Detected OS: $OS"
if command -v mkcert >/dev/null 2>&1 || command -v mkcert.exe >/dev/null 2>&1; then
echo "[O] mkcert is already installed."
echo "[!] Ensuring local CA is installed..."
(command -v mkcert.exe >/dev/null 2>&1 && mkcert.exe -install || mkcert -install)
echo "[O] Local CA configured."
return 0
fi
case "$OS" in
windows)
if ! command -v choco >/dev/null 2>&1 && ! command -v choco.exe >/dev/null 2>&1; then
echo "[X] Chocolatey not found!"
echo "Install it first: https://chocolatey.org/install"
exit 1
fi
choco install mkcert -y
;;
mac)
if ! command -v brew >/dev/null 2>&1; then
echo "[X] Homebrew not found!"
echo "Install it from https://brew.sh/"
exit 1
fi
brew install mkcert nss
;;
linux)
if command -v apt >/dev/null 2>&1; then
sudo apt update -y && sudo apt install -y mkcert libnss3-tools
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y mkcert nss-tools
elif command -v yum >/dev/null 2>&1; then
sudo yum install -y mkcert nss-tools
elif command -v zypper >/dev/null 2>&1; then
sudo zypper install -y mkcert mozilla-nss-tools
else
echo "[X] Unsupported Linux distro. Install manually:"
echo "→ https://github.com/FiloSottile/mkcert"
exit 1
fi
;;
esac
if command -v mkcert >/dev/null 2>&1 || command -v mkcert.exe >/dev/null 2>&1; then
echo "[O] mkcert installed successfully."
echo "[!] Creating local CA..."
(command -v mkcert.exe >/dev/null 2>&1 && mkcert.exe -install || mkcert -install)
echo "[O] Local CA configured."
echo "[End] mkcert installation complete."
else
echo "[X] mkcert installation failed!"
exit 1
fi
}
create_cert_dir(){
if [ ! -d "${CERT_DIR}" ]; then
echo "[!] Creating certificate directory: ${CERT_DIR}"
mkdir -p "${CERT_DIR}"
fi
}
domain_verify(){
local domain="${1}"
local doc_path="/var/www/vhosts/${domain}/html"
echo "[!] Checking if domain '${domain}' has been added..."
if docker compose exec -T ${CONT_NAME} bash -c "[ -d ${doc_path} ]" 2>/dev/null; then
echo -e "[O] Domain \033[32m${domain}\033[0m exists (document root found)"
return 0
else
echo -e "[X] Domain \033[31m${domain}\033[0m has NOT been added yet!"
echo "[!] Document root not found: ${doc_path}"
echo "[!] Please add this domain first using: bash bin/domain.sh -a ${domain}"
exit 1
fi
}
generate_cert(){
echo '[Start] Generating SSL certificate'
www_domain "${DOMAIN}"
create_cert_dir
mkdir -p "${CERT_DIR}/${DOMAIN}"
cd "${CERT_DIR}/${DOMAIN}"
echo -e "[!] Generating certificate for: \033[32m${DOMAIN}\033[0m and \033[32m${WWW_DOMAIN}\033[0m"
${MKCERT_CMD} -key-file key.pem -cert-file cert.pem "${DOMAIN}" "${WWW_DOMAIN}" >/dev/null 2>&1
if [ ${?} = 0 ]; then
echo -e "[O] Certificate generated successfully"
echo "[!] Certificate files:"
echo "${EPACE}Cert: ${CERT_DIR}/${DOMAIN}/cert.pem"
echo "${EPACE}Key: ${CERT_DIR}/${DOMAIN}/key.pem"
else
echo "[X] Failed to generate certificate"
cd ../..
rm -rf "${CERT_DIR}/${DOMAIN}"
exit 1
fi
cd - > /dev/null
echo '[End] Generating SSL certificate'
}
create_local_template(){
echo '[Start] Creating docker-local.conf template'
local source_file="/usr/local/lsws/conf/templates/docker.conf"
local dest_file="/usr/local/lsws/conf/templates/docker-local.conf"
if docker compose exec -T ${CONT_NAME} bash -c "[ -f ${dest_file} ]" 2>/dev/null; then
echo "[i] Template file already exists: ${dest_file}"
echo '[End] Creating docker-local.conf template'
return 0
fi
docker compose exec -T ${CONT_NAME} bash -c "
# Copy template file
cp ${source_file} ${dest_file}
# Remove old vhssl block and last closing brace
sed -i '/^ vhssl {/,/^ }/d; \$d' ${dest_file}
# Append new vhssl configuration
cat >> ${dest_file} <<'VHSSL_EOF'
vhssl {
keyFile /usr/local/lsws/conf/cert/\$VH_NAME/key.pem
certFile /usr/local/lsws/conf/cert/\$VH_NAME/cert.pem
certChain 1
}
}
VHSSL_EOF
# Fix ownership and permissions
chown nobody:nogroup ${dest_file} 2>/dev/null || chown lsadm:lsadm ${dest_file}
chmod 644 ${dest_file}
"
echo -e "[O] Template \033[32mdocker-local.conf\033[0m created successfully!"
echo -e " SSL certificates path: /usr/local/lsws/conf/cert/\$VH_NAME/"
echo '[End] Creating docker-local.conf template'
}
register_local_template() {
echo '[Start] Registering vhTemplate: dockerLocal'
local config_file="/usr/local/lsws/conf/httpd_config.conf"
local template_name="dockerLocal"
local template_path="conf/templates/docker-local.conf"
docker compose exec -T ${CONT_NAME} bash -c "
if ! grep -q 'vhTemplate ${template_name} {' ${config_file}; then
cat >> ${config_file} <<EOF
vhTemplate ${template_name} {
templateFile ${template_path}
listeners HTTP, HTTPS
note ${template_name}
}
EOF
echo '[✔] Template ${template_name} registered.'
else
echo '[i] Template ${template_name} already exists, skipped.'
fi
"
echo '[End] Registering vhTemplate complete.'
}
configure_litespeed(){
echo '[Start] Configuring OpenLiteSpeed for local SSL'
local cert_host_path="${CERT_DIR}/${DOMAIN}"
if [ ! -f "${cert_host_path}/cert.pem" ] || [ ! -f "${cert_host_path}/key.pem" ]; then
echo "[X] Certificate files not found on host at: ${cert_host_path}"
exit 1
fi
echo "[!] Configuring SSL for domain: ${DOMAIN}"
local lsws_conf_dir="/usr/local/lsws/conf"
local httpd_conf="${lsws_conf_dir}/httpd_config.conf"
local cert_container_path="${lsws_conf_dir}/cert/${DOMAIN}"
echo "[!] Step 1: Creating docker-local template..."
create_local_template
echo "[!] Step 2: Registering dockerLocal template..."
register_local_template
echo "[!] Step 3: Searching for Virtual Host mapped to '${DOMAIN}'..."
local vhost_name=$(docker compose exec -T ${CONT_NAME} bash -c "grep -B 2 'vhDomain.*${DOMAIN}' ${httpd_conf} | grep 'member' | awk '{print \$2}'" | tr -d '\r')
if [ -z "${vhost_name}" ]; then
echo "[X] No Virtual Host found for domain '${DOMAIN}' in ${httpd_conf}."
echo "[!] Please add this domain to your environment first (e.g., using the 'domain' script)."
exit 1
fi
echo "[O] Found Virtual Host member name: '${vhost_name}'"
echo "[!] Step 4: Checking if domain is already configured for SSL..."
if docker compose exec -T ${CONT_NAME} bash -c "sed -n '/^vhTemplate dockerLocal {/,/^}/p' ${httpd_conf} | grep -q 'member ${vhost_name}'"; then
echo -e "[O] Domain '\033[32m${DOMAIN}\033[0m' is already in 'dockerLocal' template."
echo "[!] Updating certificates and restarting..."
docker compose exec -T ${CONT_NAME} bash -c "mkdir -p ${cert_container_path}"
docker compose cp "${cert_host_path}/cert.pem" "${CONT_NAME}:${cert_container_path}/cert.pem"
docker compose cp "${cert_host_path}/key.pem" "${CONT_NAME}:${cert_container_path}/key.pem"
lsws_restart
echo "[End] Configuration complete."
exit 0
fi
echo "[!] Step 5: Copying certificates to container..."
docker compose exec -T ${CONT_NAME} bash -c "mkdir -p ${cert_container_path}"
docker compose cp "${cert_host_path}/cert.pem" "${CONT_NAME}:${cert_container_path}/cert.pem"
docker compose cp "${cert_host_path}/key.pem" "${CONT_NAME}:${cert_container_path}/key.pem"
echo "[O] Certificates copied to: ${cert_container_path}"
echo "[!] Step 6: Moving domain from 'docker' template to 'dockerLocal' template..."
docker compose exec -T ${CONT_NAME} bash -c "
# Backup httpd_config.conf
cp ${httpd_conf} ${httpd_conf}.backup.\$(date +%Y%m%d_%H%M%S)
# Find the member block for this vhost in 'docker' template
sed -i '/^vhTemplate docker {/,/^}/ {
/member ${vhost_name} {/,/}/d
}' ${httpd_conf}
# Add the member to 'dockerLocal' template
# Find the last line of dockerLocal template and insert before it
sed -i '/^vhTemplate dockerLocal {/,/^}/ {
/^}/ i\ member ${vhost_name} {\n vhDomain ${DOMAIN},www.${DOMAIN}\n }
}' ${httpd_conf}
"
if [ ${?} = 0 ]; then
echo -e "[O] Domain '\033[32m${DOMAIN}\033[0m' moved to 'dockerLocal' template"
echo "[!] Restarting OpenLiteSpeed to apply changes..."
lsws_restart
else
echo "[X] Failed to move domain to dockerLocal template"
exit 1
fi
echo '[End] Configuring OpenLiteSpeed'
}
remove_cert(){
echo '[Start] Removing SSL certificate'
local cert_host_path="${CERT_DIR}/${DOMAIN}"
local lsws_conf_dir="/usr/local/lsws/conf"
local httpd_conf="${lsws_conf_dir}/httpd_config.conf"
local cert_container_path="${lsws_conf_dir}/cert/${DOMAIN}"
echo "[!] Step 1: Finding Virtual Host for domain '${DOMAIN}'..."
local vhost_name=$(docker compose exec -T ${CONT_NAME} bash -c "grep -B 2 'vhDomain.*${DOMAIN}' ${httpd_conf} | grep 'member' | awk '{print \$2}'" | tr -d '\r')
if [ -z "${vhost_name}" ]; then
echo "[!] No Virtual Host found for domain '${DOMAIN}' in dockerLocal template"
echo "[!] Certificate may have already been removed or was never configured"
else
echo "[O] Found Virtual Host member name: '${vhost_name}'"
echo "[!] Step 2: Removing domain from 'dockerLocal' template..."
if docker compose exec -T ${CONT_NAME} bash -c "sed -n '/^vhTemplate dockerLocal {/,/^}/p' ${httpd_conf} | grep -q 'member ${vhost_name}'"; then
echo "[O] Domain is configured for SSL. Moving it back to 'docker' template..."
docker compose exec -T ${CONT_NAME} bash -c "
# Backup httpd_config.conf
cp ${httpd_conf} ${httpd_conf}.backup.\$(date +%Y%m%d_%H%M%S)
# Remove the member block from dockerLocal template
sed -i '/^vhTemplate dockerLocal {/,/^}/ {
/member ${vhost_name} {/,/}/d
}' ${httpd_conf}
# Add the member back to 'docker' template (without SSL)
sed -i '/^vhTemplate docker {/,/^}/ {
/^}/ i\ member ${vhost_name} {\n vhDomain ${DOMAIN},www.${DOMAIN}\n }
}' ${httpd_conf}
"
if [ ${?} = 0 ]; then
echo -e "[O] Domain '\033[32m${DOMAIN}\033[0m' moved back to 'docker' template"
else
echo "[X] Failed to move domain back to docker template"
fi
else
echo "[!] Domain is not in 'dockerLocal' template. No configuration changes needed."
fi
fi
echo "[!] Step 3: Removing certificate files from host..."
if [ -d "${cert_host_path}" ]; then
rm -rf "${cert_host_path}"
echo -e "[O] Removed: ${cert_host_path}"
else
echo "[!] Certificate directory not found on host: ${cert_host_path}"
fi
echo "[!] Step 4: Removing certificate files from container..."
docker compose exec -T ${CONT_NAME} bash -c "
if [ -d ${cert_container_path} ]; then
rm -rf ${cert_container_path}
echo '[O] Removed certificate directory from container: ${cert_container_path}'
else
echo '[!] Certificate directory not found in container'
fi
"
echo "[!] Step 5: Checking if dockerLocal template has any members..."
local member_count=$(docker compose exec -T ${CONT_NAME} bash -c "grep -A 20 'vhTemplate dockerLocal' ${httpd_conf} | grep -c 'member'" | tr -d '\r')
if [ "${member_count}" = "0" ]; then
echo "[!] dockerLocal template has no members, removing template..."
docker compose exec -T ${CONT_NAME} bash -c "
sed -i '/^vhTemplate dockerLocal {/,/^}/d' ${httpd_conf}
"
echo "[O] Removed empty dockerLocal template"
docker compose exec -T ${CONT_NAME} bash -c "
if [ -f ${lsws_conf_dir}/templates/docker-local.conf ]; then
rm ${lsws_conf_dir}/templates/docker-local.conf
echo '[O] Removed docker-local.conf template file'
fi
"
else
echo "[i] dockerLocal template still has ${member_count} member(s), keeping template"
fi
echo "[!] Step 6: Restarting OpenLiteSpeed..."
lsws_restart
echo ""
echo -e "\033[1m[SUCCESS] Certificate removed for domain: ${DOMAIN}\033[0m"
echo ""
echo '[End] Removing SSL certificate'
}
lsws_restart() {
docker compose exec ${CONT_NAME} su -c '/usr/local/lsws/bin/lswsctrl restart >/dev/null'
if [ ${?} = 0 ]; then
echo -e "[O] OpenLiteSpeed restarted successfully"
else
echo "[X] Failed to restart OpenLiteSpeed"
fi
}
main(){
if [ "${INSTALL}" = 'true' ]; then
install_mkcert
exit 0
fi
domain_filter "${DOMAIN}"
if [ "${REMOVE}" = 'true' ]; then
remove_cert
exit 0
fi
check_mkcert
domain_verify "${DOMAIN}"
generate_cert
configure_litespeed
}
check_input ${1}
while [ ! -z "${1}" ]; do
case ${1} in
-[hH] | -help | --help)
help_message
;;
-[dD] | -domain | --domain)
shift
check_input "${1}"
DOMAIN="${1}"
;;
-[iI] | --install)
INSTALL=true
;;
-[rR] | --remove)
REMOVE=true
;;
*)
help_message
;;
esac
shift
done
main
+6 -6
View File
@@ -33,20 +33,20 @@ check_input(){
}
lsws_restart(){
docker-compose exec ${CONT_NAME} su -c '/usr/local/lsws/bin/lswsctrl restart >/dev/null'
docker compose exec -T ${CONT_NAME} su -c '/usr/local/lsws/bin/lswsctrl restart >/dev/null'
}
apply_serial(){
docker-compose exec ${CONT_NAME} su -c "serialctl.sh --serial ${1}"
docker compose exec ${CONT_NAME} su -c "serialctl.sh --serial ${1}"
lsws_restart
}
mod_secure(){
if [ "${1}" = 'enable' ] || [ "${1}" = 'Enable' ]; then
docker-compose exec ${CONT_NAME} su -s /bin/bash root -c "owaspctl.sh --enable"
docker compose exec ${CONT_NAME} su -s /bin/bash root -c "owaspctl.sh --enable"
lsws_restart
elif [ "${1}" = 'disable' ] || [ "${1}" = 'Disable' ]; then
docker-compose exec ${CONT_NAME} su -s /bin/bash root -c "owaspctl.sh --disable"
docker compose exec ${CONT_NAME} su -s /bin/bash root -c "owaspctl.sh --disable"
lsws_restart
else
help_message
@@ -55,13 +55,13 @@ mod_secure(){
ls_upgrade(){
echo 'Upgrade web server to latest stable version.'
docker-compose exec ${CONT_NAME} su -c '/usr/local/lsws/admin/misc/lsup.sh 2>/dev/null'
docker compose exec ${CONT_NAME} su -c '/usr/local/lsws/admin/misc/lsup.sh 2>/dev/null'
}
set_web_admin(){
echo 'Update web admin password.'
local LSADPATH='/usr/local/lsws/admin'
docker-compose exec ${CONT_NAME} su -s /bin/bash lsadm -c \
docker compose exec ${CONT_NAME} su -s /bin/bash lsadm -c \
'if [ -e /usr/local/lsws/admin/fcgi-bin/admin_php ]; then \
echo "admin:$('${LSADPATH}'/fcgi-bin/admin_php -q '${LSADPATH}'/misc/htpasswd.php '${1}')" > '${LSADPATH}'/conf/htpasswd; \
else echo "admin:$('${LSADPATH}'/fcgi-bin/admin_php5 -q '${LSADPATH}'/misc/htpasswd.php '${1}')" > '${LSADPATH}'/conf/htpasswd; \
+39 -15
View File
@@ -1,28 +1,31 @@
version: '3'
services:
mysql:
image: mariadb:10.3.17
command: --max_allowed_packet=256M
image: mariadb:11.4
logging:
driver: none
command: ["--max-allowed-packet=512M"]
volumes:
- "./data/db:/var/lib/mysql:delegated"
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
restart: always
networks:
- default
litespeed:
image: litespeedtech/openlitespeed:${OLS_VERSION}-${PHP_VERSION}
container_name: litespeed
env_file:
- .env
volumes:
- ./lsws/conf:/usr/local/lsws/conf
- ./lsws/admin-conf:/usr/local/lsws/admin/conf
- ./bin/container:/usr/local/bin
- ./sites:/var/www/vhosts/
- ./acme:/root/.acme.sh/
- ./logs:/usr/local/lsws/logs/
- ./lsws/conf:/usr/local/lsws/conf
- ./lsws/admin-conf:/usr/local/lsws/admin/conf
- ./bin/container:/usr/local/bin
- ./sites:/var/www/vhosts/
- ./acme:/root/.acme.sh/
- ./logs:/usr/local/lsws/logs/
ports:
- 80:80
- 443:443
@@ -31,11 +34,32 @@ services:
restart: always
environment:
TZ: ${TimeZone}
networks:
- default
phpmyadmin:
#image: bitnami/phpmyadmin:latest
image: bitnami/phpmyadmin:5.0.2-debian-10-r72
image: phpmyadmin/phpmyadmin:${PHPMYADMIN_VERSION}
env_file:
- .env
ports:
- 8080:80
- 8443:443
environment:
DATABASE_HOST: mysql
PMA_HOST: mysql
restart: always
networks:
- default
redis:
image: "redis:alpine"
logging:
driver: none
# command: redis-server --requirepass 8b405f60665e48f795752e534d93b722
volumes:
- ./redis/data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
environment:
- REDIS_REPLICATION_MODE=master
restart: always
networks:
- default
networks:
default:
driver: bridge