First commit.

This commit is contained in:
Mehdi (OSX) 2023-11-22 15:17:13 +05:00
commit 734638870b
10 changed files with 431 additions and 0 deletions

208
.gitattributes vendored Normal file
View File

@ -0,0 +1,208 @@
# Taken from: https://github.com/alexkaratarakis/gitattributes/blob/master/Web.gitattributes
## GITATTRIBUTES FOR WEB PROJECTS
#
# These settings are for any web project.
#
# Details per file setting:
# text These files should be normalized (i.e. convert CRLF to LF).
# binary These files are binary and should be left untouched.
#
# Note that binary is a macro for -text -diff.
######################################################################
# Auto detect
## Handle line endings automatically for files detected as
## text and leave all files detected as binary untouched.
## This will handle all files NOT defined below.
* text=auto
# Source code
*.bash text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.coffee text
*.css text diff=css
*.htm text diff=html
*.html text diff=html
*.inc text
*.ini text
*.js text
*.json text
*.jsx text
*.less text
*.ls text
*.map text -diff
*.od text
*.onlydata text
*.php text diff=php
*.pl text
*.ps1 text eol=crlf
*.py text diff=python
*.rb text diff=ruby
*.sass text
*.scm text
*.scss text diff=css
*.sh text eol=lf
.husky/* text eol=lf
*.sql text
*.styl text
*.tag text
*.ts text
*.tsx text
*.xml text
*.xhtml text diff=html
# Docker
Dockerfile text
# Documentation
*.ipynb text eol=lf
*.markdown text diff=markdown
*.md text diff=markdown
*.mdwn text diff=markdown
*.mdown text diff=markdown
*.mkd text diff=markdown
*.mkdn text diff=markdown
*.mdtxt text
*.mdtext text
*.txt text
AUTHORS text
CHANGELOG text
CHANGES text
CONTRIBUTING text
COPYING text
copyright text
*COPYRIGHT* text
INSTALL text
license text
LICENSE text
NEWS text
readme text
*README* text
TODO text
# Templates
*.dot text
*.ejs text
*.erb text
*.haml text
*.handlebars text
*.hbs text
*.hbt text
*.jade text
*.latte text
*.mustache text
*.njk text
*.phtml text
*.svelte text
*.tmpl text
*.tpl text
*.twig text
*.vue text
# Configs
*.cnf text
*.conf text
*.config text
.editorconfig text
.env text
.gitattributes text
.gitconfig text
.htaccess text
*.lock text -diff
package.json text eol=lf
package-lock.json text eol=lf -diff
pnpm-lock.yaml text eol=lf -diff
.prettierrc text
yarn.lock text -diff
*.toml text
*.yaml text
*.yml text
browserslist text
Makefile text
makefile text
# Heroku
Procfile text
# Graphics
*.ai binary
*.bmp binary
*.eps binary
*.gif binary
*.gifv binary
*.ico binary
*.jng binary
*.jp2 binary
*.jpg binary
*.jpeg binary
*.jpx binary
*.jxr binary
*.pdf binary
*.png binary
*.psb binary
*.psd binary
# SVG treated as an asset (binary) by default.
*.svg text
# If you want to treat it as binary,
# use the following line instead.
# *.svg binary
*.svgz binary
*.tif binary
*.tiff binary
*.wbmp binary
*.webp binary
# Audio
*.kar binary
*.m4a binary
*.mid binary
*.midi binary
*.mp3 binary
*.ogg binary
*.ra binary
# Video
*.3gpp binary
*.3gp binary
*.as binary
*.asf binary
*.asx binary
*.avi binary
*.fla binary
*.flv binary
*.m4v binary
*.mng binary
*.mov binary
*.mp4 binary
*.mpeg binary
*.mpg binary
*.ogv binary
*.swc binary
*.swf binary
*.webm binary
# Archives
*.7z binary
*.gz binary
*.jar binary
*.rar binary
*.tar binary
*.zip binary
# Fonts
*.ttf binary
*.eot binary
*.otf binary
*.woff binary
*.woff2 binary
# Executables
*.exe binary
*.pyc binary
# RC files (like .babelrc or .eslintrc)
*.*rc text
# Ignore files (like .npmignore or .gitignore)
*.*ignore text

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/certs/**
!/certs/.gitkeep

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/untitled1.iml" filepath="$PROJECT_DIR$/.idea/untitled1.iml" />
</modules>
</component>
</project>

19
.idea/php.xml generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

8
.idea/untitled1.iml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

57
README.md Normal file
View File

@ -0,0 +1,57 @@
**Check config options in** `generate-certs.sh`
---
- It uses certbot's docker to generate LetsEncrypt SSL certificates, and it comes with simple script to generate and renew certificate for **single domain.**
- It **does not support multiple domains**. But you can create certificate for test.com, abc.test.com, *.test.com (wildcard).
---
## Info:
- This script will **create** SSL certificates based on `${new_ssl_command}`.
- If the `${live_certs_dir}` and `${live_certs_dir}/cert.pem` exist then certificate is **renewed** based on `${renew_command}`
- Post hook is only executed:
1. If a new ssl certificate is created.
2. If certificate is renewed (test is done by comparing ${live_certs_dir}/cert.pem modified time to last one).
---
## Usage:
- Set configuration in `generate-certs.sh`
- Set executable permission: `chmod +x generate-certs.sh`
- Run: `generate-certs.sh`
- After the certificates are created:
- Make sure to mount both `certs/test.com/live` and `certs/test.com/archive` directory, and use `live/*.pem` certificates in your nginx config.
- Because archive directory has actual files, but live directory has symlink to archive. In archive, certs are stored like this fullchain1.pem, cert1.pem and number is increased based on renewals. But live folder has direct certificates without number like cert.pem, fullchain.pem
- Also use: https://github.com/certbot/certbot/blob/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
---
## Example nginx config:
```
server {
listen 443;
server_name test.com;
#SSL - Set in production.
ssl_certificate /etc/letsencrypt/live/test.com/fullchain.pem; #managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.com/privkey.pem; #managed by Certbot
include /etc/nginx/commons/letsencrypt-options-ssl-nginx.conf;
}
```
## Important:
- **In case of errors, try clearing certs/\* folder and retry.** _(Although keep .gitkeep file.)_
- Use `dry_run=true` to test certbot instead of actually creating/renewing certificates.
---
## Cron:
- Run this file under cron to keep the certificates updated.
- Certbot generate certificates with expiry of 90days, so run this script every day once.
- If a certificate is renewed (based on change of last-modified time, to existing certificate) then `posthook` is executed.
- You can restart nginx in `posthook`, to reload used certificates.
- Example:
- `nano /etc/cron.d/generate-certs-for-test.com`
- `0 1 * * * root /script-location/generate-certs.sh > /script-location/generate-certs.log`

0
certs/.gitkeep Normal file
View File

115
generate-certs.sh Executable file
View File

@ -0,0 +1,115 @@
#!/bin/bash
#CONFIG:
dry_run=true
cloudflare_token='' #Create it from Cloudflare, and limit it the DNZ zone of your domain.
live_certs_dir="certs/live/calm.biz"; #Script will check this directory for empty, to determine to create or renew ssl certificates.
new_ssl_command="docker run --rm -v ./certs:/etc/letsencrypt -v #cloudflare_token_file#:/certbot-cloudflare certbot/dns-cloudflare certonly #dry_run_arg# --dns-cloudflare --dns-cloudflare-credentials /certbot-cloudflare -d calm.biz -d \*.calm.biz -d temp.temp.calm.biz --preferred-challenges dns-01 --preferred-chain 'ISRG Root X1' --non-interactive --dns-cloudflare-propagation-seconds 20 --agree-tos --email w3goodies.com@gmail.com";
renew_command="docker run --rm -v ./certs:/etc/letsencrypt -v #cloudflare_token_file#:/certbot-cloudflare certbot/dns-cloudflare renew #dry_run_arg# --non-interactive --agree-tos --email w3goodies.com@gmail.com --no-random-sleep-on-renew"
post_hook="docker-compose restart nginx" #posthook is executed if certificate is created for first time, or if "${live_certs_dir}/cert.pem" file is modified (based on checking last modified time).
#END CONFIG
#chdir to current dir.
cd "$(dirname "$0")"
#remove trailing slash from live_certs_dir
live_certs_dir=${live_certs_dir%/}
separator="=========="
#Set cloudflare token in file because certbot requires it inside a file.
cloudflare_token_file="./cf-tmp"
echo "dns_cloudflare_api_token = ${cloudflare_token}" > ${cloudflare_token_file}
chmod 600 ${cloudflare_token_file}
new_ssl_command=${new_ssl_command//#cloudflare_token_file#/$cloudflare_token_file}
renew_command=${renew_command//#cloudflare_token_file#/$cloudflare_token_file}
#Set dry run flag in command if true.
dry_run_arg=""
if [ "$dry_run" = true ] ; then
dry_run_arg=" --dry-run"
fi
new_ssl_command=${new_ssl_command//#dry_run_arg#/$dry_run_arg}
renew_command=${renew_command//#dry_run_arg#/$dry_run_arg}
echo ""
#Check if certificate exist
live_cert_file="${live_certs_dir}/cert.pem"
if [ -d "$live_certs_dir" ] && [ -f "$live_cert_file" ]
then
#Renew
last_modified_time=$(date -r "${live_cert_file}")
echo "${separator}"
echo "Certificates folder exist: ${live_certs_dir}"
echo "TRYING TO RENEW CERTIFICATES..."
echo "${separator}"
if [ "$dry_run" = true ] ; then
echo -e "\n${separator}\n[DRY-RUN ENABLED]\n${separator}\n"
else
echo -e "\n${separator}\n"
fi
echo -e "Output from renew command:\n"
eval "${renew_command}"
if [ $? -eq 0 ]; then
echo -e "${separator}\nCommand exited successfully.\n${separator}\n"
#Check if file is modified.
new_modified_time=$(date -r "${live_cert_file}")
if [ "$last_modified_time" != "$new_modified_time" ]; then
echo -e "${separator}\nChange found in: ${live_cert_file}, therefore executing posthook.\n${separator}\n";
eval "${post_hook}"
if [ $? -eq 0 ]; then
echo -e "\n${separator}\nPost hook successfully executed.\n${separator}\n"
else
echo -e "\n${separator}\nERROR! Unable to execute post hook.\n${separator}"
fi
else
echo -e "${separator}\nNo change in certificate so posthook is ignored.\n${separator}"
fi
else
echo -e "\n${separator}\nERROR! Exiting.\n${separator}"
fi
else
#Create
echo "${separator}"
echo "Certificates folder does not exist: ${live_certs_dir}"
echo "TRYING TO CREATE SSL CERTIFICATES..."
if [ "$dry_run" = true ] ; then
echo -e "\n${separator}\n[DRY-RUN ENABLED]\n${separator}\n"
else
echo -e "\n${separator}\n"
fi
echo -e "Output from new ssl command:\n"
eval "${new_ssl_command}"
if [ $? -eq 0 ]; then
echo -e "\n${separator}\nCommand exited successfully therefore executing posthook.\n${separator}\n"
eval "${post_hook}"
if [ $? -eq 0 ]; then
echo "Post hook successfully executed."
else
echo -e "\n${separator}\nERROR! Unable to execute post hook.\n${separator}"
fi
else
echo -e "\n${separator}\nERROR! Exiting.\n${separator}"
fi
fi
echo ""
#Remove tmp file
rm -f ${cloudflare_token_file}