This commit is contained in:
Alexey Berezhok
2024-03-19 22:05:27 +03:00
commit 346a50856b
1572 changed files with 182163 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
ROLE='admin'
COMMANDS='v-add-user,v-delete-user,v-suspend-user,v-unsuspend-user,v-change-user-shell,v-list-user,v-list-users,v-make-tmp-file,v-add-domain,v-change-user-package,v-make-tmp-file,v-change-user-password'

View File

@@ -0,0 +1,2 @@
ROLE='user'
COMMANDS='v-list-mail-domains,v-list-mail-domain,v-list-mail-account,v-list-mail-accounts,v-list-mail-account-autoreply,v-delete-mail-account,v-delete-mail-account-alias,v-delete-mail-account-autoreply,v-delete-mail-account-forward,v-delete-mail-account-fwd-only,v-add-mail-account,v-add-mail-account-alias,v-add-mail-account-autoreply,v-add-mail-account-forward,v-add-mail-account-fwd-only,v-change-mail-account-password,v-change-mail-account-quota,v-suspend-mail-account,v-suspend-mail-accounts,v-unsuspend-mail-account,v-unsuspend-mail-accounts'

View File

@@ -0,0 +1,2 @@
ROLE='admin'
COMMANDS='v-add-database-temp-user,v-delete-database-temp-user'

View File

@@ -0,0 +1,2 @@
ROLE='user'
COMMANDS='v-purge-nginx-cache,v-list-web-domains,v-list-web-domain'

View File

@@ -0,0 +1,2 @@
ROLE='admin'
COMMANDS='v-list-users,v-list-sys-config,v-list-user,v-add-cron-restart-job,v-delete-dns-domains-src,v-insert-dns-domain,v-insert-dns-record,v-insert-dns-records,v-rebuild-dns-domains,v-rebuild-dns-domain,v-delete-dns-record,v-make-tmp-file,v-insert-dns-domain,v-delete-dns-domain'

View File

@@ -0,0 +1,2 @@
ROLE='user'
COMMANDS='v-list-dns-records,v-change-dns-record'

View File

@@ -0,0 +1,5 @@
disable_plaintext_auth = no
auth_username_format = %Lu
auth_verbose = yes
auth_mechanisms = plain login
!include auth-passwdfile.conf.ext

View File

@@ -0,0 +1 @@
log_path = /var/log/dovecot.log

View File

@@ -0,0 +1,8 @@
mail_privileged_group = mail
mail_access_groups = mail
mail_location = maildir:%h/mail/%d/%n
pop3_uidl_format = %08Xu%08Xv
mailbox_list_index = yes
mailbox_idle_check_interval = 30 secs
maildir_copy_with_hardlinks = yes

View File

@@ -0,0 +1,31 @@
service imap-login {
inet_listener imap {
}
inet_listener imaps {
}
}
service pop3-login {
inet_listener pop3 {
}
inet_listener pop3s {
}
}
service imap {
}
service pop3 {
}
service auth {
extra_groups = mail
unix_listener auth-client {
group = mail
mode = 0660
user = dovecot
}
user = dovecot
}

View File

@@ -0,0 +1,13 @@
ssl = yes
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
ssl_cert = </usr/local/hestia/ssl/certificate.crt
ssl_key = </usr/local/hestia/ssl/certificate.key
# From and up to version 2.2
#ssl_dh_parameters_length = 4096
# From version 2.3
ssl_dh = </etc/ssl/dhparam.pem

View File

@@ -0,0 +1,59 @@
##
## IMAP specific settings
##
protocol imap {
# Maximum IMAP command line length. Some clients generate very long command
# lines with huge mailboxes, so you may need to raise this if you get
# "Too long argument" or "IMAP command line too large" errors often.
#imap_max_line_length = 64k
# Maximum number of IMAP connections allowed for a user from each IP address.
# NOTE: The username is compared case-sensitively.
#mail_max_userip_connections = 10
# Space separated list of plugins to load (default is global mail_plugins).
#mail_plugins = $mail_plugins
mail_plugins = quota imap_quota
# IMAP logout format string:
# %i - total number of bytes read from client
# %o - total number of bytes sent to client
#imap_logout_format = bytes=%i/%o
# Override the IMAP CAPABILITY response. If the value begins with '+',
# add the given capabilities on top of the defaults (e.g. +XFOO XBAR).
#imap_capability =
# How long to wait between "OK Still here" notifications when client is
# IDLEing.
#imap_idle_notify_interval = 2 mins
# ID field names and values to send to clients. Using * as the value makes
# Dovecot use the default value. The following fields have default values
# currently: name, version, os, os-version, support-url, support-email.
#imap_id_send =
# ID fields sent by client to log. * means everything.
#imap_id_log =
# Workarounds for various client bugs:
# delay-newmail:
# Send EXISTS/RECENT new mail notifications only when replying to NOOP
# and CHECK commands. Some clients ignore them otherwise, for example OSX
# Mail (<v2.1). Outlook Express breaks more badly though, without this it
# may show user "Message no longer in server" errors. Note that OE6 still
# breaks even with this workaround if synchronization is set to
# "Headers Only".
# tb-extra-mailbox-sep:
# Thunderbird gets somehow confused with LAYOUT=fs (mbox and dbox) and
# adds extra '/' suffixes to mailbox names. This option causes Dovecot to
# ignore the extra '/' instead of treating it as invalid mailbox name.
# tb-lsub-flags:
# Show \Noselect flags for LSUB replies with LAYOUT=fs (e.g. mbox).
# This makes Thunderbird realize they aren't selectable and show them
# greyed out, instead of only later giving "not selectable" popup error.
#
# The list is space-separated.
#imap_client_workarounds =
}

View File

@@ -0,0 +1,92 @@
##
## POP3 specific settings
##
protocol pop3 {
# Don't try to set mails non-recent or seen with POP3 sessions. This is
# mostly intended to reduce disk I/O. With maildir it doesn't move files
# from new/ to cur/, with mbox it doesn't write Status-header.
#pop3_no_flag_updates = no
# Support LAST command which exists in old POP3 specs, but has been removed
# from new ones. Some clients still wish to use this though. Enabling this
# makes RSET command clear all \Seen flags from messages.
#pop3_enable_last = no
# If mail has X-UIDL header, use it as the mail's UIDL.
#pop3_reuse_xuidl = no
# Keep the mailbox locked for the entire POP3 session.
#pop3_lock_session = no
# POP3 requires message sizes to be listed as if they had CR+LF linefeeds.
# Many POP3 servers violate this by returning the sizes with LF linefeeds,
# because it's faster to get. When this setting is enabled, Dovecot still
# tries to do the right thing first, but if that requires opening the
# message, it fallbacks to the easier (but incorrect) size.
#pop3_fast_size_lookups = no
# POP3 UIDL (unique mail identifier) format to use. You can use following
# variables, along with the variable modifiers described in
# doc/wiki/Variables.txt (e.g. %Uf for the filename in uppercase)
#
# %v - Mailbox's IMAP UIDVALIDITY
# %u - Mail's IMAP UID
# %m - MD5 sum of the mailbox headers in hex (mbox only)
# %f - filename (maildir only)
# %g - Mail's GUID
#
# If you want UIDL compatibility with other POP3 servers, use:
# UW's ipop3d : %08Xv%08Xu
# Courier : %f or %v-%u (both might be used simultaneosly)
# Cyrus (<= 2.1.3) : %u
# Cyrus (>= 2.1.4) : %v.%u
# Dovecot v0.99.x : %v.%u
# tpop3d : %Mf
#
# Note that Outlook 2003 seems to have problems with %v.%u format which was
# Dovecot's default, so if you're building a new server it would be a good
# idea to change this. %08Xu%08Xv should be pretty fail-safe.
#
#pop3_uidl_format = %08Xu%08Xv
# Permanently save UIDLs sent to POP3 clients, so pop3_uidl_format changes
# won't change those UIDLs. Currently this works only with Maildir.
#pop3_save_uidl = no
# What to do about duplicate UIDLs if they exist?
# allow: Show duplicates to clients.
# rename: Append a temporary -2, -3, etc. counter after the UIDL.
#pop3_uidl_duplicates = allow
# POP3 logout format string:
# %i - total number of bytes read from client
# %o - total number of bytes sent to client
# %t - number of TOP commands
# %p - number of bytes sent to client as a result of TOP command
# %r - number of RETR commands
# %b - number of bytes sent to client as a result of RETR command
# %d - number of deleted messages
# %m - number of messages (before deletion)
# %s - mailbox size in bytes (before deletion)
# %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly
#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s
# Maximum number of POP3 connections allowed for a user from each IP address.
# NOTE: The username is compared case-sensitively.
#mail_max_userip_connections = 10
# Space separated list of plugins to load (default is global mail_plugins).
#mail_plugins = $mail_plugins
mail_plugins = quota
# Workarounds for various client bugs:
# outlook-no-nuls:
# Outlook and Outlook Express hang if mails contain NUL characters.
# This setting replaces them with 0x80 character.
# oe-ns-eoh:
# Outlook Express and Netscape Mail breaks if end of headers-line is
# missing. This option simply sends it if it's missing.
# The list is space-separated.
#pop3_client_workarounds =
}

View File

@@ -0,0 +1,84 @@
##
## Quota configuration.
##
# Note that you also have to enable quota plugin in mail_plugins setting.
# <doc/wiki/Quota.txt>
##
## Quota limits
##
# Quota limits are set using "quota_rule" parameters. To get per-user quota
# limits, you can set/override them by returning "quota_rule" extra field
# from userdb. It's also possible to give mailbox-specific limits, for example
# to give additional 100 MB when saving to Trash:
plugin {
#quota_rule = *:storage=1G
#quota_rule2 = Trash:storage=+100M
# LDA/LMTP allows saving the last mail to bring user from under quota to
# over quota, if the quota doesn't grow too high. Default is to allow as
# long as quota will stay under 10% above the limit. Also allowed e.g. 10M.
#quota_grace = 10%%
# Quota plugin can also limit the maximum accepted mail size.
#quota_max_mail_size = 100M
}
##
## Quota warnings
##
# You can execute a given command when user exceeds a specified quota limit.
# Each quota root has separate limits. Only the command for the first
# exceeded limit is excecuted, so put the highest limit first.
# The commands are executed via script service by connecting to the named
# UNIX socket (quota-warning below).
# Note that % needs to be escaped as %%, otherwise "% " expands to empty.
plugin {
#quota_warning = storage=95%% quota-warning 95 %u
#quota_warning2 = storage=80%% quota-warning 80 %u
}
# Example quota-warning service. The unix listener's permissions should be
# set in a way that mail processes can connect to it. Below example assumes
# that mail processes run as vmail user. If you use mode=0666, all system users
# can generate quota warnings to anyone.
#service quota-warning {
# executable = script /usr/local/bin/quota-warning.sh
# user = dovecot
# unix_listener quota-warning {
# user = vmail
# }
#}
##
## Quota backends
##
# Multiple backends are supported:
# dirsize: Find and sum all the files found from mail directory.
# Extremely SLOW with Maildir. It'll eat your CPU and disk I/O.
# dict: Keep quota stored in dictionary (eg. SQL)
# maildir: Maildir++ quota
# fs: Read-only support for filesystem quota
plugin {
#quota = dirsize:User quota
quota = maildir:User quota
#quota = dict:User quota::proxy::quota
#quota = fs:User quota
}
# Multiple quota roots are also possible, for example this gives each user
# their own 100MB quota and one shared 1GB quota within the domain:
plugin {
#quota = dict:user::proxy::quota
#quota2 = dict:domain:%d:proxy::quota_domain
#quota_rule = *:storage=102400
#quota2_rule = *:storage=1048576
}

View File

@@ -0,0 +1,9 @@
passdb {
driver = passwd-file
args = scheme=MD5-CRYPT username_format=%n /etc/exim4/domains/%d/passwd
}
userdb {
driver = passwd-file
args = username_format=%n /etc/exim4/domains/%d/passwd
}

View File

@@ -0,0 +1,66 @@
protocols = imap pop3
listen = *, ::
base_dir = /run/dovecot/
login_greeting = Mail Delivery Agent
!include conf.d/*.conf
!include_try conf.d/domains/*.conf
service stats {
unix_listener stats-writer {
group = mail
mode = 0660
user = dovecot
}
}
namespace {
type = private
separator = /
inbox = yes
list = yes
mailbox Archive {
auto = subscribe
special_use = \Archive
}
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
mailbox "Deleted Messages" {
auto = no
special_use = \Trash
}
mailbox Spam {
auto = subscribe
special_use = \Junk
}
mailbox Junk {
auto = no
special_use = \Junk
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Mail" {
auto = no
special_use = \Sent
}
mailbox "Sent Messages" {
auto = no
special_use = \Sent
}
}

View File

@@ -0,0 +1,88 @@
##
## ManageSieve specific settings
##
# Uncomment to enable managesieve protocol:
protocols = $protocols sieve
# Service definitions
service managesieve-login {
inet_listener sieve {
port = 4190
}
#inet_listener sieve_deprecated {
# port = 2000
#}
# Number of connections to handle before starting a new process. Typically
# the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
# is faster. <doc/wiki/LoginProcess.txt>
#service_count = 1
# Number of processes to always keep waiting for more connections.
#process_min_avail = 0
# If you set service_count=0, you probably need to grow this.
#vsz_limit = 64M
}
#service managesieve {
# Max. number of ManageSieve processes (connections)
#process_limit = 1024
#}
# Service configuration
protocol sieve {
# Maximum ManageSieve command line length in bytes. ManageSieve usually does
# not involve overly long command lines, so this setting will not normally
# need adjustment
managesieve_max_line_length = 65536
# Maximum number of ManageSieve connections allowed for a user from each IP
# address.
# NOTE: The username is compared case-sensitively.
#mail_max_userip_connections = 10
# Space separated list of plugins to load (none known to be useful so far).
# Do NOT try to load IMAP plugins here.
#mail_plugins =
# MANAGESIEVE logout format string:
# %i - total number of bytes read from client
# %o - total number of bytes sent to client
# %{put_bytes} - Number of bytes saved using PUTSCRIPT command
# %{put_count} - Number of scripts saved using PUTSCRIPT command
# %{get_bytes} - Number of bytes read using GETCRIPT command
# %{get_count} - Number of scripts read using GETSCRIPT command
# %{get_bytes} - Number of bytes processed using CHECKSCRIPT command
# %{get_count} - Number of scripts checked using CHECKSCRIPT command
# %{deleted_count} - Number of scripts deleted using DELETESCRIPT command
# %{renamed_count} - Number of scripts renamed using RENAMESCRIPT command
#managesieve_logout_format = bytes=%i/%o
# To fool ManageSieve clients that are focused on CMU's timesieved you can
# specify the IMPLEMENTATION capability that Dovecot reports to clients.
# For example: 'Cyrus timsieved v2.2.13'
managesieve_implementation_string = Dovecot Pigeonhole
# Explicitly specify the SIEVE and NOTIFY capability reported by the server
# before login. If left unassigned these will be reported dynamically
# according to what the Sieve interpreter supports by default (after login
# this may differ depending on the user).
#managesieve_sieve_capability =
#managesieve_notify_capability =
# The maximum number of compile errors that are returned to the client upon
# script upload or script verification.
#managesieve_max_compile_errors = 5
# Refer to 90-sieve.conf for script quota configuration and configuration of
# Sieve execution limits.
#log_path = /var/log/dovecot-sieve-errors.log
#info_log_path = /var/log/dovecot-sieve.log
}

View File

@@ -0,0 +1,44 @@
# Sieve Extprograms plugin configuration
# Don't forget to add the sieve_extprograms plugin to the sieve_plugins setting.
# Also enable the extensions you need (one or more of vnd.dovecot.pipe,
# vnd.dovecot.filter and vnd.dovecot.execute) by adding these to the
# sieve_extensions or sieve_global_extensions settings. Restricting these
# extensions to a global context using sieve_global_extensions is recommended.
plugin {
# The directory where the program sockets are located for the
# vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension
# respectively. The name of each unix socket contained in that directory
# directly maps to a program-name referenced from the Sieve script.
#sieve_pipe_socket_dir = sieve-pipe
#sieve_filter_socket_dir = sieve-filter
#sieve_execute_socket_dir = sieve-execute
# The directory where the scripts are located for direct execution by the
# vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension
# respectively. The name of each script contained in that directory
# directly maps to a program-name referenced from the Sieve script.
#sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe
#sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter
#sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute
}
# An example program service called 'do-something' to pipe messages to
#service do-something {
# Define the executed script as parameter to the sieve service
#executable = script /usr/lib/dovecot/sieve-pipe/do-something.sh
# Use some unprivileged user for executing the program
#user = dovenull
# The unix socket located in the sieve_pipe_socket_dir (as defined in the
# plugin {} section above)
#unix_listener sieve-pipe/do-something {
# LDA/LMTP must have access
# user = vmail
# mode = 0600
#}
#}

View File

@@ -0,0 +1,211 @@
##
## Settings for the Sieve interpreter
##
# Do not forget to enable the Sieve plugin in 15-lda.conf and 20-lmtp.conf
# by adding it to the respective mail_plugins= settings.
# The Sieve interpreter can retrieve Sieve scripts from several types of
# locations. The default `file' location type is a local filesystem path
# pointing to a Sieve script file or a directory containing multiple Sieve
# script files. More complex setups can use other location types such as
# `ldap' or `dict' to fetch Sieve scripts from remote databases.
#
# All settings that specify the location of one ore more Sieve scripts accept
# the following syntax:
#
# location = [<type>:]path[;<option>[=<value>][;...]]
#
# If the type prefix is omitted, the script location type is 'file' and the
# location is interpreted as a local filesystem path pointing to a Sieve script
# file or directory. Refer to Pigeonhole wiki or INSTALL file for more
# information.
plugin {
# The location of the user's main Sieve script or script storage. The LDA
# Sieve plugin uses this to find the active script for Sieve filtering at
# delivery. The "include" extension uses this location for retrieving
# :personal" scripts. This is also where the ManageSieve service will store
# the user's scripts, if supported.
#
# Currently only the 'file:' location type supports ManageSieve operation.
# Other location types like 'dict:' and 'ldap:' can currently only
# be used as a read-only script source ().
#
# For the 'file:' type: use the ';active=' parameter to specify where the
# active script symlink is located.
# For other types: use the ';name=' parameter to specify the name of the
# default/active script.
#sieve = file:~/sieve;active=~/.dovecot.sieve
sieve = file:~/mail/%d/%n/sieve;active=~/mail/%d/%n/dovecot.sieve
# The default Sieve script when the user has none. This is the location of a
# global sieve script file, which gets executed ONLY if user's personal Sieve
# script doesn't exist. Be sure to pre-compile this script manually using the
# sievec command line tool if the binary is not stored in a global location.
# --> See sieve_before for executing scripts before the user's personal
# script.
#sieve_default = /var/lib/dovecot/sieve/default.sieve
# The name by which the default Sieve script (as configured by the
# sieve_default setting) is visible to the user through ManageSieve.
#sieve_default_name =
# Location for ":global" include scripts as used by the "include" extension.
#sieve_global =
# The location of a Sieve script that is run for any message that is about to
# be discarded; i.e., it is not delivered anywhere by the normal Sieve
# execution. This only happens when the "implicit keep" is canceled, by e.g.
# the "discard" action, and no actions that deliver the message are executed.
# This "discard script" can prevent discarding the message, by executing
# alternative actions. If the discard script does nothing, the message is
# still discarded as it would be when no discard script is configured.
#sieve_discard =
# Location Sieve of scripts that need to be executed before the user's
# personal script. If a 'file' location path points to a directory, all the
# Sieve scripts contained therein (with the proper `.sieve' extension) are
# executed. The order of execution within that directory is determined by the
# file names, using a normal 8bit per-character comparison.
#
# Multiple script locations can be specified by appending an increasing number
# to the setting name. The Sieve scripts found from these locations are added
# to the script execution sequence in the specified order. Reading the
# numbered sieve_before settings stops at the first missing setting, so no
# numbers may be skipped.
#sieve_before = /var/lib/dovecot/sieve.d/
#sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain
#sieve_before3 = (etc...)
# Identical to sieve_before, only the specified scripts are executed after the
# user's script (only when keep is still in effect!). Multiple script
# locations can be specified by appending an increasing number.
#sieve_after =
#sieve_after2 =
#sieve_after2 = (etc...)
# Which Sieve language extensions are available to users. By default, all
# supported extensions are available, except for deprecated extensions or
# those that are still under development. Some system administrators may want
# to disable certain Sieve extensions or enable those that are not available
# by default. This setting can use '+' and '-' to specify differences relative
# to the default. For example `sieve_extensions = +imapflags' will enable the
# deprecated imapflags extension in addition to all extensions were already
# enabled by default.
sieve_extensions = +notify +imapflags
# Which Sieve language extensions are ONLY available in global scripts. This
# can be used to restrict the use of certain Sieve extensions to administrator
# control, for instance when these extensions can cause security concerns.
# This setting has higher precedence than the `sieve_extensions' setting
# (above), meaning that the extensions enabled with this setting are never
# available to the user's personal script no matter what is specified for the
# `sieve_extensions' setting. The syntax of this setting is similar to the
# `sieve_extensions' setting, with the difference that extensions are
# enabled or disabled for exclusive use in global scripts. Currently, no
# extensions are marked as such by default.
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
# The Pigeonhole Sieve interpreter can have plugins of its own. Using this
# setting, the used plugins can be specified. Check the Dovecot wiki
# (wiki2.dovecot.org) or the pigeonhole website
# (http://pigeonhole.dovecot.org) for available plugins.
# The sieve_extprograms plugin is included in this release.
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_pipe_bin_dir = /etc/dovecot/sieve
# The maximum size of a Sieve script. The compiler will refuse to compile any
# script larger than this limit. If set to 0, no limit on the script size is
# enforced.
#sieve_max_script_size = 1M
# The maximum number of actions that can be performed during a single script
# execution. If set to 0, no limit on the total number of actions is enforced.
#sieve_max_actions = 32
# The maximum number of redirect actions that can be performed during a single
# script execution. If set to 0, no redirect actions are allowed.
#sieve_max_redirects = 4
# The maximum number of personal Sieve scripts a single user can have. If set
# to 0, no limit on the number of scripts is enforced.
# (Currently only relevant for ManageSieve)
#sieve_quota_max_scripts = 0
# The maximum amount of disk storage a single user's scripts may occupy. If
# set to 0, no limit on the used amount of disk storage is enforced.
# (Currently only relevant for ManageSieve)
#sieve_quota_max_storage = 0
# The primary e-mail address for the user. This is used as a default when no
# other appropriate address is available for sending messages. If this setting
# is not configured, either the postmaster or null "<>" address is used as a
# sender, depending on the action involved. This setting is important when
# there is no message envelope to extract addresses from, such as when the
# script is executed in IMAP.
#sieve_user_email =
# The path to the file where the user log is written. If not configured, a
# default location is used. If the main user's personal Sieve (as configured
# with sieve=) is a file, the logfile is set to <filename>.log by default. If
# it is not a file, the default user log file is ~/.dovecot.sieve.log.
#sieve_user_log =
# Specifies what envelope sender address is used for redirected messages.
# The following values are supported for this setting:
#
# "sender" - The sender address is used (default).
# "recipient" - The final recipient address is used.
# "orig_recipient" - The original recipient is used.
# "user_email" - The user's primary address is used. This is
# configured with the "sieve_user_email" setting. If
# that setting is unconfigured, "user_mail" is equal to
# "recipient".
# "postmaster" - The postmaster_address configured for the LDA.
# "<user@domain>" - Redirected messages are always sent from user@domain.
# The angle brackets are mandatory. The null "<>" address
# is also supported.
#
# This setting is ignored when the envelope sender is "<>". In that case the
# sender of the redirected message is also always "<>".
#sieve_redirect_envelope_from = sender
## TRACE DEBUGGING
# Trace debugging provides detailed insight in the operations performed by
# the Sieve script. These settings apply to both the LDA Sieve plugin and the
# IMAPSIEVE plugin.
#
# WARNING: On a busy server, this functionality can quickly fill up the trace
# directory with a lot of trace files. Enable this only temporarily and as
# selective as possible.
# The directory where trace files are written. Trace debugging is disabled if
# this setting is not configured or if the directory does not exist. If the
# path is relative or it starts with "~/" it is interpreted relative to the
# current user's home directory.
#sieve_trace_dir =
# The verbosity level of the trace messages. Trace debugging is disabled if
# this setting is not configured. Possible values are:
#
# "actions" - Only print executed action commands, like keep,
# fileinto, reject and redirect.
# "commands" - Print any executed command, excluding test commands.
# "tests" - Print all executed commands and performed tests.
# "matching" - Print all executed commands, performed tests and the
# values matched in those tests.
#sieve_trace_level =
# Enables highly verbose debugging messages that are usually only useful for
# developers.
#sieve_trace_debug = no
# Enables showing byte code addresses in the trace output, rather than only
# the source line numbers.
#sieve_trace_addresses = no
# This setting determines whether vacation messages are sent with the SMTP MAIL FROM envelope address set to the recipient address of the Sieve script owner.
sieve_vacation_send_from_recipient = yes
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Filegator\Services\Archiver\Adapters;
use Filegator\Container\Container;
use Filegator\Services\Archiver\ArchiverInterface;
use Filegator\Services\Service;
use Filegator\Services\Storage\Filesystem as Storage;
use Filegator\Services\Tmpfs\TmpfsInterface;
use function Hestiacp\quoteshellarg\quoteshellarg;
class HestiaZipArchiver extends ZipArchiver implements Service, ArchiverInterface {
protected $container;
public function __construct(TmpfsInterface $tmpfs, Container $container) {
$this->tmpfs = $tmpfs;
$this->container = $container;
}
public function uncompress(string $source, string $destination, Storage $storage) {
$auth = $this->container->get("Filegator\Services\Auth\AuthInterface");
$v_user = basename($auth->user()->getUsername());
if (!strlen($v_user)) {
return;
}
if (strpos($source, "/home") === false) {
$source = "/home/$v_user/" . $source;
}
if (strpos($destination, "/home") === false) {
$destination = "/home/$v_user/" . $destination;
}
exec(
"sudo /usr/local/hestia/bin/v-extract-fs-archive " .
quoteshellarg($v_user) .
" " .
quoteshellarg($source) .
" " .
quoteshellarg($destination),
$output,
$return_var,
);
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of the FileGator package.
*
* (c) Milos Stojanovic <alcalbg@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
*/
namespace Filegator\Services\Auth\Adapters;
use Filegator\Services\Auth\AuthInterface;
use Filegator\Services\Auth\User;
use Filegator\Services\Auth\UsersCollection;
use Filegator\Services\Service;
use function Hestiacp\quoteshellarg\quoteshellarg;
/**
* @codeCoverageIgnore
*/
class HestiaAuth implements Service, AuthInterface {
protected $permissions = [];
protected $private_repos = false;
protected $hestia_user = "";
public function init(array $config = []) {
if (isset($_SESSION["user"])) {
$v_user = $_SESSION["user"];
}
if (!empty($_SESSION["look"])) {
if (isset($_SESSION["look"]) && $_SESSION["userContext"] === "admin") {
$v_user = $_SESSION["look"];
}
if (
$_SESSION["look"] == "admin" &&
$_SESSION["POLICY_SYSTEM_PROTECTED_ADMIN"] == "yes"
) {
// Go away do not login
header("Location: /");
exit();
}
}
$this->hestia_user = $v_user;
$this->permissions = isset($config["permissions"]) ? (array) $config["permissions"] : [];
$this->private_repos = isset($config["private_repos"])
? (bool) $config["private_repos"]
: false;
}
public function user(): ?User {
$cmd = "/usr/bin/sudo /usr/local/hestia/bin/v-list-user";
exec($cmd . " " . quoteshellarg($this->hestia_user) . " json", $output, $return_var);
if ($return_var == 0) {
$data = json_decode(implode("", $output), true);
$hestia_user_info = $data[$this->hestia_user];
return $this->transformUser($hestia_user_info);
}
return $this->getGuest();
}
public function transformUser($hstuser): User {
$user = new User();
$user->setUsername($this->hestia_user);
$user->setName($this->hestia_user . " (" . $hstuser["NAME"] . ")");
$user->setRole("user");
$user->setPermissions($this->permissions);
$user->setHomedir("/");
return $user;
}
public function authenticate($username, $password): bool {
# Auth is handled by Hestia
return false;
}
public function forget() {
// Logout return to Hestia
return $this->getGuest();
}
public function store(User $user) {
return null; // not used
}
public function update($username, User $user, $password = ""): User {
// Password change is handled by Hestia
return $this->user();
}
public function add(User $user, $password): User {
return new User(); // not used
}
public function delete(User $user) {
return true; // not used
}
public function find($username): ?User {
return null; // not used
}
public function allUsers(): UsersCollection {
return new UsersCollection(); // not used
}
public function getGuest(): User {
$guest = new User();
$guest->setUsername("guest");
$guest->setName("Guest");
$guest->setRole("guest");
$guest->setHomedir("/");
$guest->setPermissions([]);
return $guest;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the FileGator package.
*
* (c) Milos Stojanovic <alcalbg@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
*/
namespace Filegator\Services\Session\Adapters;
use Filegator\Kernel\Request;
use Filegator\Services\Service;
use Filegator\Services\Session\Session;
use Filegator\Services\Session\SessionStorageInterface;
class SessionStorage implements Service, SessionStorageInterface {
protected $request;
protected $config;
public function __construct(Request $request) {
$this->request = $request;
}
public function init(array $config = []) {
// we don't have a previous session attached
if (!$this->getSession()) {
$handler = $config["handler"];
$session = new Session($handler());
//$session->setName('filegator');
$this->setSession($session);
}
}
public function save() {
$this->getSession()->save();
}
public function set(string $key, $data) {
return $this->getSession()->set($key, $data);
}
public function get(string $key, $default = null) {
return $this->getSession() ? $this->getSession()->get($key, $default) : $default;
}
public function invalidate() {
if (!$this->getSession()->isStarted()) {
$this->getSession()->start();
}
$this->getSession()->invalidate();
}
private function setSession(Session $session) {
return $this->request->setSession($session);
}
private function getSession(): ?Session {
return $this->request->getSession();
}
}

View File

@@ -0,0 +1,47 @@
{
"name": "filegator/filegator",
"description": "Filegator",
"license": "MIT",
"type": "project",
"config": {
"platform": {
"php": "7.2.5"
}
},
"require": {
"php": "^7.2",
"monolog/monolog": "^1.24",
"nikic/fast-route": "^1.3",
"symfony/security-csrf": "^4.4",
"symfony/http-foundation": "^4.4",
"dibi/dibi": "^4.1",
"php-di/php-di": "^6.0",
"rakit/validation": "^1.1",
"league/flysystem": "^1.1",
"league/flysystem-ziparchive": "^1.0",
"league/flysystem-sftp": "^1.0",
"hestiacp/phpquoteshellarg": "^1.0"
},
"authors": [
{
"name": "Milos Stojanovic",
"email": "alcalbg@gmail.com"
}
],
"autoload": {
"psr-4": {
"Filegator\\": "backend"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/backend/"
}
},
"require-dev": {
"phpunit/phpunit": "^8.0",
"symfony/var-dumper": "^4.4",
"league/flysystem-memory": "^1.0",
"phpstan/phpstan": "^0.11.8"
}
}

4771
install/common/filegator/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
<?php
use function Hestiacp\quoteshellarg\quoteshellarg;
$dist_config = require __DIR__ . "/configuration_sample.php";
$dist_config["public_path"] = "/fm/";
$dist_config["frontend_config"]["app_name"] = "File Manager - Hestia Control Panel";
$dist_config["frontend_config"]["logo"] = "../images/logo.svg";
$dist_config["frontend_config"]["editable"] = [
".txt",
".css",
".js",
".json",
".ts",
".html",
".php",
".py",
".yml",
".xml",
".md",
".log",
".csv",
".conf",
".config",
".ini",
".scss",
".service",
".sh",
".env",
".example",
".htaccess",
".twig",
".tpl",
".yaml",
];
$dist_config["frontend_config"]["guest_redirection"] = "/login/";
$dist_config["frontend_config"]["upload_max_size"] = 1024 * 1024 * 1024;
$dist_config["services"]["Filegator\Services\Storage\Filesystem"]["config"][
"adapter"
] = function () {
if (!empty($_SESSION["INACTIVE_SESSION_TIMEOUT"])) {
if ($_SESSION["INACTIVE_SESSION_TIMEOUT"] * 60 + $_SESSION["LAST_ACTIVITY"] < time()) {
$v_user = quoteshellarg($_SESSION["user"]);
$v_session_id = quoteshellarg($_SESSION["token"]);
exec(
"/usr/local/hestia/bin/v-log-user-logout " . $v_user . " " . $v_session_id,
$output,
$return_var,
);
unset($_SESSION);
session_unset();
session_destroy();
session_start();
echo '<meta http-equiv="refresh" content="0; url=/">';
exit();
} else {
$_SESSION["LAST_ACTIVITY"] = time();
}
} else {
echo '<meta http-equiv="refresh" content="0; url=/">';
}
if (isset($_SESSION["user"])) {
$v_user = $_SESSION["user"];
}
if (!empty($_SESSION["look"])) {
if (isset($_SESSION["look"]) && $_SESSION["userContext"] === "admin") {
$v_user = $_SESSION["look"];
}
if (
isset($_SESSION["look"]) &&
$_SESSION["look"] == "admin" &&
$_SESSION["POLICY_SYSTEM_PROTECTED_ADMIN"] == "yes"
) {
header("Location: /");
}
}
# Create filemanager sftp key if missing and trash it after 30 min
if (!file_exists("/home/" . basename($v_user) . "/.ssh/hst-filemanager-key")) {
exec(
"sudo /usr/local/hestia/bin/v-add-user-sftp-key " .
quoteshellarg(basename($v_user)) .
" 30",
$output,
$return_var,
);
// filemanager also requires .ssh chmod o+x ... hopefully we can improve it to g+x or u+x someday
// current minimum for filemanager: chmod 0701 .ssh
shell_exec("sudo chmod o+x " . quoteshellarg("/home/" . basename($v_user) . "/.ssh"));
}
if (!isset($_SESSION["SFTP_PORT"])) {
exec("sudo /usr/local/hestia/bin/v-list-sys-sshd-port json", $output, $result);
$port = json_decode(implode("", $output));
if (is_numeric($port[0]) && $port[0] > 0) {
$_SESSION["SFTP_PORT"] = $port[0];
} elseif (
preg_match('/^\s*Port\s+(\d+)$/im', file_get_contents("/etc/ssh/sshd_config"), $matches)
) {
$_SESSION["SFTP_PORT"] = $matches[1] ?? 22;
} else {
$_SESSION["SFTP_PORT"] = 22;
}
}
preg_match(
'/(Hestia SFTP Chroot\nMatch User)(.*)/i',
file_get_contents("/etc/ssh/sshd_config"),
$matches,
);
$user_list = explode(",", $matches[2]);
if (in_array($v_user, $user_list)) {
$root = "/";
} else {
$root = "/home/" . $v_user;
}
return new \League\Flysystem\Sftp\SftpAdapter([
"host" => "127.0.0.1",
"port" => intval($_SESSION["SFTP_PORT"]),
"username" => basename($v_user),
"privateKey" => "/home/" . basename($v_user) . "/.ssh/hst-filemanager-key",
"root" => $root,
"timeout" => 10,
"directoryPerm" => 0755,
]);
};
$dist_config["services"]["Filegator\Services\Archiver\ArchiverInterface"] = [
"handler" => "\Filegator\Services\Archiver\Adapters\HestiaZipArchiver",
"config" => [],
];
$dist_config["services"]["Filegator\Services\Auth\AuthInterface"] = [
"handler" => "\Filegator\Services\Auth\Adapters\HestiaAuth",
"config" => [
"permissions" => ["read", "write", "upload", "download", "batchdownload", "zip"],
"private_repos" => false,
],
];
$dist_config["services"]["Filegator\Services\View\ViewInterface"]["config"] = [
"add_to_head" => '
<style>
.logo {
width: 46px;
}
</style>
',
"add_to_body" => '
<script>
var checkVueLoaded = setInterval(function() {
if (document.getElementsByClassName("container").length) {
clearInterval(checkVueLoaded);
var navProfile = document.getElementsByClassName("navbar-item profile")[0]; navProfile.replaceWith(navProfile.cloneNode(true))
document.getElementsByClassName("navbar-item logout")[0].text="Exit to Control Panel \u00BB";
div = document.getElementsByClassName("container")[0];
callback = function(){
if (document.getElementsByClassName("navbar-item logout")[0]){
if ( document.getElementsByClassName("navbar-item logout")[0].text != "Exit to Control Panel \u00BB" ){
var navProfile = document.getElementsByClassName("navbar-item profile")[0]; navProfile.replaceWith(navProfile.cloneNode(true))
document.getElementsByClassName("navbar-item logout")[0].text="Exit to Control Panel \u00BB";
}
}
}
config = {
childList:true,
subtree:true
}
observer = new MutationObserver(callback);
observer.observe(div,config);
}
}, 200);
</script>',
];
return $dist_config;

View File

@@ -0,0 +1,35 @@
#!/bin/bash
# Script and blacklist urls partially taken from:
# https://github.com/trick77/ipset-blacklist/blob/master/ipset-blacklist.conf
#
BLACKLISTS=(
"https://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1" # Project Honey Pot Directory of Dictionary Attacker IPs
"https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1" # TOR Exit Nodes
"https://www.maxmind.com/en/high-risk-ip-sample-list" # MaxMind GeoIP Anonymous Proxies
"https://danger.rulez.sk/projects/bruteforceblocker/blist.php" # BruteForceBlocker IP List
"https://www.spamhaus.org/drop/drop.lasso" # Spamhaus Don't Route Or Peer List (DROP)
"https://cinsscore.com/list/ci-badguys.txt" # C.I. Army Malicious IP List
"https://lists.blocklist.de/lists/all.txt" # blocklist.de attackers
"https://blocklist.greensnow.co/greensnow.txt" # GreenSnow
"https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" # Firehol Level 1
"https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/stopforumspam_7d.ipset" # Stopforumspam via Firehol
)
IP_BLACKLIST_TMP=$(mktemp)
for i in "${BLACKLISTS[@]}"; do
IP_TMP=$(mktemp)
((HTTP_RC = $(curl -L --connect-timeout 10 --max-time 10 -o "$IP_TMP" -s -w "%{http_code}" "$i")))
if ((HTTP_RC == 200 || HTTP_RC == 302 || HTTP_RC == 0)); then # "0" because file:/// returns 000
command grep -Po '^(?:\d{1,3}\.){3}\d{1,3}(?:/\d{1,2})?' "$IP_TMP" | sed -r 's/^0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)$/\1.\2.\3.\4/' >> "$IP_BLACKLIST_TMP"
elif ((HTTP_RC == 503)); then
echo >&2 -e "\\nUnavailable (${HTTP_RC}): $i"
else
echo >&2 -e "\\nWarning: curl returned HTTP response code $HTTP_RC for URL $i"
fi
rm -f "$IP_TMP"
done
sed -r -e '/^(0\.0\.0\.0|10\.|127\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\.|192\.168\.|22[4-9]\.|23[0-9]\.)/d' "$IP_BLACKLIST_TMP" | sort -n | sort -mu
rm -f "$IP_BLACKLIST_TMP"

View File

@@ -0,0 +1,10 @@
RULE='1' ACTION='ACCEPT' PROTOCOL='ICMP' PORT='0' IP='0.0.0.0/0' COMMENT='PING' SUSPENDED='no' TIME='17:13:48' DATE='2014-09-16'
RULE='2' ACTION='ACCEPT' PROTOCOL='TCP' PORT='8083' IP='0.0.0.0/0' COMMENT='HESTIA' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='3' ACTION='ACCEPT' PROTOCOL='TCP' PORT='143,993' IP='0.0.0.0/0' COMMENT='IMAP' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='4' ACTION='ACCEPT' PROTOCOL='TCP' PORT='110,995' IP='0.0.0.0/0' COMMENT='POP3' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='5' ACTION='ACCEPT' PROTOCOL='TCP' PORT='25,465,587' IP='0.0.0.0/0' COMMENT='SMTP' SUSPENDED='no' TIME='21:47:04' DATE='2018-11-07'
RULE='6' ACTION='ACCEPT' PROTOCOL='TCP' PORT='53' IP='0.0.0.0/0' COMMENT='DNS' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='7' ACTION='ACCEPT' PROTOCOL='UDP' PORT='53' IP='0.0.0.0/0' COMMENT='DNS' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='8' ACTION='ACCEPT' PROTOCOL='TCP' PORT='21,12000-12100' IP='0.0.0.0/0' COMMENT='FTP' SUSPENDED='no' TIME='07:40:16' DATE='2014-05-25'
RULE='9' ACTION='ACCEPT' PROTOCOL='TCP' PORT='80,443' IP='0.0.0.0/0' COMMENT='WEB' SUSPENDED='no' TIME='17:04:27' DATE='2014-09-24'
RULE='10' ACTION='ACCEPT' PROTOCOL='TCP' PORT='22' IP='0.0.0.0/0' COMMENT='SSH' SUSPENDED='no' TIME='17:14:41' DATE='2014-09-16'

View File

@@ -0,0 +1,20 @@
WEB_TEMPLATE='default'
PROXY_TEMPLATE='default'
BACKEND_TEMPLATE='default'
DNS_TEMPLATE='default'
WEB_DOMAINS='unlimited'
WEB_ALIASES='unlimited'
DNS_DOMAINS='unlimited'
DNS_RECORDS='unlimited'
MAIL_DOMAINS='unlimited'
MAIL_ACCOUNTS='unlimited'
RATE_LIMIT='200'
DATABASES='unlimited'
CRON_JOBS='unlimited'
DISK_QUOTA='unlimited'
BANDWIDTH='unlimited'
NS='ns1.domain.tld,ns2.domain.tld'
SHELL='nologin'
BACKUPS='1'
TIME='18:00:00'
DATE='2019-01-15'

View File

@@ -0,0 +1,20 @@
WEB_TEMPLATE='default'
PROXY_TEMPLATE='default'
BACKEND_TEMPLATE='default'
DNS_TEMPLATE='default'
WEB_DOMAINS='1'
WEB_ALIASES='1'
DNS_DOMAINS='1'
DNS_RECORDS='unlimited'
MAIL_DOMAINS='1'
MAIL_ACCOUNTS='1'
RATE_LIMIT='200'
DATABASES='0'
CRON_JOBS='unlimited'
DISK_QUOTA='unlimited'
BANDWIDTH='unlimited'
NS='ns1.domain.tld,ns2.domain.tld'
SHELL='nologin'
BACKUPS='1'
TIME='00:00:00'
DATE='2022-01-20'

View File

@@ -0,0 +1,36 @@
<?php
/* PHPmyadmin config for Hestia 1.3.3 > */
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* All directives are explained in documentation in the doc/ folder
* or at <https://docs.phpmyadmin.net/>.
*
* @package PhpMyAdmin
*/
declare(strict_types=1);
/**
* This is needed for cookie based authentication to encrypt password in
* cookie. Needs to be 32 chars long.
*/
$cfg["blowfish_secret"] = "%blowfish_secret%"; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/**
* Directories for saving/loading files from server
*/
$cfg["UploadDir"] = "";
$cfg["SaveDir"] = "";
/**
* You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/
//start with 1 other wise it doesn't work
$i = 1;
foreach (glob("/etc/phpmyadmin/conf.d/*.php") as $filename) {
include $filename;
/*Don't remove / alter code here below this will add SSO support for all servers*/
//Add Hestia SSO code here
$i++;
}

View File

@@ -0,0 +1,389 @@
-- --------------------------------------------------------
-- SQL Commands to set up the pmadb as described in the documentation.
--
-- This file is meant for use with MySQL 5 and above!
--
-- This script expects the user pma to already be existing. If we would put a
-- line here to create him too many users might just use this script and end
-- up with having the same password for the controluser.
--
-- This user "pma" must be defined in config.inc.php (controluser/controlpass)
--
-- Please don't forget to set up the tablenames in config.inc.php
--
-- --------------------------------------------------------
--
-- Database : `phpmyadmin`
--
CREATE DATABASE IF NOT EXISTS `phpmyadmin` DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
USE phpmyadmin;
-- --------------------------------------------------------
--
-- Privileges
--
-- (activate this statement if necessary)
-- GRANT SELECT, INSERT, DELETE, UPDATE, ALTER ON `phpmyadmin`.* TO
-- 'pma'@localhost;
-- --------------------------------------------------------
--
-- Table structure for table `pma__usergroups`
--
CREATE TABLE
IF NOT EXISTS `pma__usergroups` (
`usergroup` varchar(64) NOT NULL,
`tab` varchar(64) NOT NULL,
`allowed` enum ('Y', 'N') NOT NULL DEFAULT 'N',
PRIMARY KEY (`usergroup`, `tab`, `allowed`)
) COMMENT = 'User groups with configured menu items' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__designer_coords`
--
CREATE TABLE
IF NOT EXISTS `pma__designer_coords` (
`db_name` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`table_name` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`x` int (11) DEFAULT NULL,
`y` int (11) DEFAULT NULL,
`v` tinyint (4) DEFAULT NULL,
`h` tinyint (4) DEFAULT NULL,
PRIMARY KEY (`db_name`, `table_name`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8 COLLATE = utf8_bin COMMENT = 'Table coordinates for Designer';
-- --------------------------------------------------------
--
-- Table structure for table `pma__bookmark`
--
CREATE TABLE
IF NOT EXISTS `pma__bookmark` (
`id` int (11) NOT NULL auto_increment,
`dbase` varchar(255) NOT NULL default '',
`user` varchar(255) NOT NULL default '',
`label` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
`query` text NOT NULL,
PRIMARY KEY (`id`)
) COMMENT = 'Bookmarks' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__column_info`
--
CREATE TABLE
IF NOT EXISTS `pma__column_info` (
`id` int (5) unsigned NOT NULL auto_increment,
`db_name` varchar(64) NOT NULL default '',
`table_name` varchar(64) NOT NULL default '',
`column_name` varchar(64) NOT NULL default '',
`comment` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
`mimetype` varchar(255) COLLATE utf8_general_ci NOT NULL default '',
`transformation` varchar(255) NOT NULL default '',
`transformation_options` varchar(255) NOT NULL default '',
`input_transformation` varchar(255) NOT NULL default '',
`input_transformation_options` varchar(255) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY `db_name` (`db_name`, `table_name`, `column_name`)
) COMMENT = 'Column information for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__history`
--
CREATE TABLE
IF NOT EXISTS `pma__history` (
`id` bigint (20) unsigned NOT NULL auto_increment,
`username` varchar(64) NOT NULL default '',
`db` varchar(64) NOT NULL default '',
`table` varchar(64) NOT NULL default '',
`timevalue` timestamp NOT NULL default CURRENT_TIMESTAMP,
`sqlquery` text NOT NULL,
PRIMARY KEY (`id`),
KEY `username` (`username`, `db`, `table`, `timevalue`)
) COMMENT = 'SQL history for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__pdf_pages`
--
CREATE TABLE
IF NOT EXISTS `pma__pdf_pages` (
`db_name` varchar(64) NOT NULL default '',
`page_nr` int (10) unsigned NOT NULL auto_increment,
`page_descr` varchar(50) COLLATE utf8_general_ci NOT NULL default '',
PRIMARY KEY (`page_nr`),
KEY `db_name` (`db_name`)
) COMMENT = 'PDF relation pages for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__recent`
--
CREATE TABLE
IF NOT EXISTS `pma__recent` (
`username` varchar(64) NOT NULL,
`tables` text NOT NULL,
PRIMARY KEY (`username`)
) COMMENT = 'Recently accessed tables' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__favorite`
--
CREATE TABLE
IF NOT EXISTS `pma__favorite` (
`username` varchar(64) NOT NULL,
`tables` text NOT NULL,
PRIMARY KEY (`username`)
) COMMENT = 'Favorite tables' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__table_uiprefs`
--
CREATE TABLE
IF NOT EXISTS `pma__table_uiprefs` (
`username` varchar(64) NOT NULL,
`db_name` varchar(64) NOT NULL,
`table_name` varchar(64) NOT NULL,
`prefs` text NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`username`, `db_name`, `table_name`)
) COMMENT = 'Tables'' UI preferences' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__relation`
--
CREATE TABLE
IF NOT EXISTS `pma__relation` (
`master_db` varchar(64) NOT NULL default '',
`master_table` varchar(64) NOT NULL default '',
`master_field` varchar(64) NOT NULL default '',
`foreign_db` varchar(64) NOT NULL default '',
`foreign_table` varchar(64) NOT NULL default '',
`foreign_field` varchar(64) NOT NULL default '',
PRIMARY KEY (`master_db`, `master_table`, `master_field`),
KEY `foreign_field` (`foreign_db`, `foreign_table`)
) COMMENT = 'Relation table' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__table_coords`
--
CREATE TABLE
IF NOT EXISTS `pma__table_coords` (
`db_name` varchar(64) NOT NULL default '',
`table_name` varchar(64) NOT NULL default '',
`pdf_page_number` int (11) NOT NULL default '0',
`x` float unsigned NOT NULL default '0',
`y` float unsigned NOT NULL default '0',
PRIMARY KEY (`db_name`, `table_name`, `pdf_page_number`)
) COMMENT = 'Table coordinates for phpMyAdmin PDF output' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__table_info`
--
CREATE TABLE
IF NOT EXISTS `pma__table_info` (
`db_name` varchar(64) NOT NULL default '',
`table_name` varchar(64) NOT NULL default '',
`display_field` varchar(64) NOT NULL default '',
PRIMARY KEY (`db_name`, `table_name`)
) COMMENT = 'Table information for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__tracking`
--
CREATE TABLE
IF NOT EXISTS `pma__tracking` (
`db_name` varchar(64) NOT NULL,
`table_name` varchar(64) NOT NULL,
`version` int (10) unsigned NOT NULL,
`date_created` datetime NOT NULL,
`date_updated` datetime NOT NULL,
`schema_snapshot` text NOT NULL,
`schema_sql` text,
`data_sql` longtext,
`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,
`tracking_active` int (1) unsigned NOT NULL default '1',
PRIMARY KEY (`db_name`, `table_name`, `version`)
) COMMENT = 'Database changes tracking for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__userconfig`
--
CREATE TABLE
IF NOT EXISTS `pma__userconfig` (
`username` varchar(64) NOT NULL,
`timevalue` timestamp NOT NULL default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`config_data` text NOT NULL,
PRIMARY KEY (`username`)
) COMMENT = 'User preferences storage for phpMyAdmin' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__users`
--
CREATE TABLE
IF NOT EXISTS `pma__users` (
`username` varchar(64) NOT NULL,
`usergroup` varchar(64) NOT NULL,
PRIMARY KEY (`username`, `usergroup`)
) COMMENT = 'Users and their assignments to user groups' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__usergroups`
--
CREATE TABLE
IF NOT EXISTS `pma__usergroups` (
`usergroup` varchar(64) NOT NULL,
`tab` varchar(64) NOT NULL,
`allowed` enum ('Y', 'N') NOT NULL DEFAULT 'N',
PRIMARY KEY (`usergroup`, `tab`, `allowed`)
) COMMENT = 'User groups with configured menu items' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__navigationhiding`
--
CREATE TABLE
IF NOT EXISTS `pma__navigationhiding` (
`username` varchar(64) NOT NULL,
`item_name` varchar(64) NOT NULL,
`item_type` varchar(64) NOT NULL,
`db_name` varchar(64) NOT NULL,
`table_name` varchar(64) NOT NULL,
PRIMARY KEY (
`username`,
`item_name`,
`item_type`,
`db_name`,
`table_name`
)
) COMMENT = 'Hidden items of navigation tree' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__savedsearches`
--
CREATE TABLE
IF NOT EXISTS `pma__savedsearches` (
`id` int (5) unsigned NOT NULL auto_increment,
`username` varchar(64) NOT NULL default '',
`db_name` varchar(64) NOT NULL default '',
`search_name` varchar(64) NOT NULL default '',
`search_data` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_savedsearches_username_dbname` (`username`, `db_name`, `search_name`)
) COMMENT = 'Saved searches' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__central_columns`
--
CREATE TABLE
IF NOT EXISTS `pma__central_columns` (
`db_name` varchar(64) NOT NULL,
`col_name` varchar(64) NOT NULL,
`col_type` varchar(64) NOT NULL,
`col_length` text,
`col_collation` varchar(64) NOT NULL,
`col_isNull` boolean NOT NULL,
`col_extra` varchar(255) default '',
`col_default` text,
PRIMARY KEY (`db_name`, `col_name`)
) COMMENT = 'Central list of columns' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__designer_settings`
--
CREATE TABLE
IF NOT EXISTS `pma__designer_settings` (
`username` varchar(64) NOT NULL,
`settings_data` text NOT NULL,
PRIMARY KEY (`username`)
) COMMENT = 'Settings related to Designer' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;
-- --------------------------------------------------------
--
-- Table structure for table `pma__export_templates`
--
CREATE TABLE
IF NOT EXISTS `pma__export_templates` (
`id` int (5) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL,
`export_type` varchar(10) NOT NULL,
`template_name` varchar(64) NOT NULL,
`template_data` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_user_type_template` (`username`, `export_type`, `template_name`)
) COMMENT = 'Saved export templates' DEFAULT CHARACTER
SET
utf8 COLLATE utf8_bin;

View File

@@ -0,0 +1,213 @@
<?php
/* Hestia way to enable support for SSO to PHPmyAdmin */
/* To install please run v-add-sys-pma-sso */
/* Following keys will get replaced when calling v-add-sys-pma-sso */
define("PHPMYADMIN_KEY", "%PHPMYADMIN_KEY%");
define("API_HOST_NAME", "%API_HOST_NAME%");
define("API_HESTIA_PORT", "%API_HESTIA_PORT%");
define("API_KEY", "%API_KEY%");
class Hestia_API {
/** @var string */
public $hostname;
/** @var string */
public $key;
/** @var string */
public $pma_key;
/** @var string */
private $api_url;
public function __construct() {
$this->hostname = "https://" . API_HOST_NAME . ":" . API_HESTIA_PORT . "/api/";
$this->key = API_KEY;
$this->pma_key = PHPMYADMIN_KEY;
}
/* Creates curl request */
public function request($postvars) {
$postdata = http_build_query($postvars);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $this->hostname);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
$answer = curl_exec($curl);
return $answer;
}
/* Creates an new temp user in mysql */
public function create_temp_user($database, $user, $host) {
$post_request = [
"hash" => $this->key,
"returncode" => "no",
"cmd" => "v-add-database-temp-user",
"arg1" => $user,
"arg2" => $database,
"arg3" => "mysql",
"arg4" => $host,
];
$request = $this->request($post_request);
$json = json_decode($request);
if (json_last_error() == JSON_ERROR_NONE) {
return $json;
} else {
trigger_error("Unable to connect over API please check api connection", E_USER_WARNING);
return false;
}
}
/* Delete an new temp user in mysql */
public function delete_temp_user($database, $user, $dbuser, $host) {
$post_request = [
"hash" => $this->key,
"returncode" => "yes",
"cmd" => "v-delete-database-temp-user",
"arg1" => $user,
"arg2" => $database,
"arg3" => $dbuser,
"arg4" => "mysql",
"arg5" => $host,
];
$request = $this->request($post_request);
if (is_numeric($request) && $request == 0) {
return true;
} else {
return false;
}
}
public function get_user_ip() {
// Saving user IPs to the session for preventing session hijacking
$user_combined_ip = [];
if ($_SERVER["REMOTE_ADDR"] != $_SERVER["SERVER_ADDR"]) {
$user_combined_ip[] = $_SERVER["REMOTE_ADDR"];
}
if (isset($_SERVER["HTTP_CLIENT_IP"])) {
$user_combined_ip .= "|" . $_SERVER["HTTP_CLIENT_IP"];
}
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_X_FORWARDED_FOR"]) {
$user_combined_ip[] = $_SERVER["HTTP_X_FORWARDED_FOR"];
}
}
if (isset($_SERVER["HTTP_FORWARDED_FOR"])) {
if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_FORWARDED_FOR"]) {
$user_combined_ip[] = $_SERVER["HTTP_FORWARDED_FOR"];
}
}
if (isset($_SERVER["HTTP_X_FORWARDED"])) {
if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_X_FORWARDED"]) {
$user_combined_ip[] = $_SERVER["HTTP_X_FORWARDED"];
}
}
if (isset($_SERVER["HTTP_FORWARDED"])) {
if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_FORWARDED"]) {
$user_combined_ip[] = "|" . $_SERVER["HTTP_FORWARDED"];
}
}
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
$user_combined_ip[] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
}
return implode("|", $user_combined_ip);
}
}
function verify_token($database, $user, $ip, $time, $token) {
if (!password_verify($database . $user . $ip . $time . PHPMYADMIN_KEY, $token)) {
if (
!password_verify(
$database . $user . $_SERVER["SERVER_ADDR"] . "|" . $ip . $time . PHPMYADMIN_KEY,
$token,
)
) {
trigger_error(
"Access denied: There is a security token mismatch " . $time,
E_USER_WARNING,
);
session_invalid();
}
}
return;
}
/* Need to have cookie visible from parent directory */
session_set_cookie_params(0, "/", "", true, true);
/* Create signon session */
$session_name = "SignonSession";
session_name($session_name);
@session_start();
function session_invalid() {
global $session_name;
//delete all current sessions
session_destroy();
setcookie($session_name, null, -1, "/");
header("Location: " . dirname($_SERVER["PHP_SELF"]) . "/index.php");
die();
}
$api = new Hestia_API();
if (!empty($_GET)) {
if (isset($_GET["logout"])) {
$api->delete_temp_user(
$_SESSION["HESTIA_sso_database"],
$_SESSION["HESTIA_sso_user"],
$_SESSION["PMA_single_signon_user"],
$_SESSION["HESTIA_sso_host"],
);
//remove session
session_invalid();
} else {
if (isset($_GET["user"]) && isset($_GET["hestia_token"])) {
$database = $_GET["database"];
$user = $_GET["user"];
$host = "localhost";
$token = $_GET["hestia_token"];
if (is_numeric($_GET["exp"])) {
$time = $_GET["exp"];
} else {
$time = 0;
}
if ($time + 60 > time()) {
//note: Possible issues with cloudflare due to ip obfuscation
$ip = $api->get_user_ip();
verify_token($database, $user, $ip, $time, $token);
$id = session_id();
//create a new temp user
$data = $api->create_temp_user($database, $user, $host);
if ($data) {
$_SESSION["PMA_single_signon_user"] = $data->login->user;
$_SESSION["PMA_single_signon_password"] = $data->login->password;
$_SESSION["PMA_single_signon_host"] = $host;
//save database / username to be used for sending logout notification.
$_SESSION["HESTIA_sso_user"] = $user;
$_SESSION["HESTIA_sso_database"] = $database;
$_SESSION["HESTIA_sso_host"] = $host;
@session_write_close();
setcookie($session_name, $id, 0, "/");
header("Location: " . dirname($_SERVER["PHP_SELF"]) . "/index.php");
die();
} else {
session_invalid();
}
} else {
trigger_error(
"Link has been expired: System time: " .
time() .
" / Time provided in link: " .
$time,
E_USER_WARNING,
);
session_invalid();
}
}
}
} else {
session_invalid();
}

View File

@@ -0,0 +1,103 @@
#!/bin/bash
#
# phpmyadmin-fixer
#
# Fixes for phpmyadmin (configuration storage and some extended features)
#
# Original Version by Pavel Galkin (https://skurudo.ru)
# https://github.com/skurudo/phpmyadmin-fixer
#
# Changed some lines to fit to Hestia Configuration.
#
PASS=$(gen_pass)
#ubuntu phpmyadmin path
pmapath="/etc/phpmyadmin/conf.d/01-localhost.php"
echo "<?php " >> $pmapath
echo "\$cfg['Servers'][\$i]['host'] = 'localhost';" >> $pmapath
echo "\$cfg['Servers'][\$i]['port'] = '3306';" >> $pmapath
echo "\$cfg['Servers'][\$i]['favorite'] = 'pma__favorite';" >> $pmapath
echo "\$cfg['Servers'][\$i]['usergroups'] = 'pma__usergroups';" >> $pmapath
echo "\$cfg['Servers'][\$i]['central_columns'] = 'pma__central_columns';" >> $pmapath
echo "\$cfg['Servers'][\$i]['designer_settings'] = 'pma__designer_settings';" >> $pmapath
echo "\$cfg['Servers'][\$i]['export_templates'] = 'pma__export_templates';" >> $pmapath
echo "\$cfg['Servers'][\$i]['savedsearches'] = 'pma__savedsearches';" >> $pmapath
echo "\$cfg['Servers'][\$i]['navigationhiding'] = 'pma__navigationhiding';" >> $pmapath
echo "\$cfg['Servers'][\$i]['users'] = 'pma__users';" >> $pmapath
echo "\$cfg['Servers'][\$i]['usergroups'] = 'pma__usergroups';" >> $pmapath
echo "\$cfg['Servers'][\$i]['pmadb'] = 'phpmyadmin';" >> $pmapath
echo "\$cfg['Servers'][\$i]['controluser'] = 'pma';" >> $pmapath
echo "\$cfg['Servers'][\$i]['controlpass'] = '$PASS';" >> $pmapath
echo "\$cfg['Servers'][\$i]['bookmarktable'] = 'pma__bookmark';" >> $pmapath
echo "\$cfg['Servers'][\$i]['relation'] = 'pma__relation';" >> $pmapath
echo "\$cfg['Servers'][\$i]['userconfig'] = 'pma__userconfig';" >> $pmapath
echo "\$cfg['Servers'][\$i]['table_info'] = 'pma__table_info';" >> $pmapath
echo "\$cfg['Servers'][\$i]['column_info'] = 'pma__column_info';" >> $pmapath
echo "\$cfg['Servers'][\$i]['history'] = 'pma__history';" >> $pmapath
echo "\$cfg['Servers'][\$i]['recent'] = 'pma__recent';" >> $pmapath
echo "\$cfg['Servers'][\$i]['table_uiprefs'] = 'pma__table_uiprefs';" >> $pmapath
echo "\$cfg['Servers'][\$i]['tracking'] = 'pma__tracking';" >> $pmapath
echo "\$cfg['Servers'][\$i]['table_coords'] = 'pma__table_coords';" >> $pmapath
echo "\$cfg['Servers'][\$i]['pdf_pages'] = 'pma__pdf_pages';" >> $pmapath
echo "\$cfg['Servers'][\$i]['designer_coords'] = 'pma__designer_coords';" >> $pmapath
echo "\$cfg['Servers'][\$i]['hide_db'] = 'information_schema';" >> $pmapath
#SOME WORK with DATABASE (table / user)
PMADB=phpmyadmin
PMAUSER=pma
#DROP USER and TABLE
#mysql -uroot <<MYSQL_PMA1
#DROP USER '$PMAUSER'@'localhost';
#DROP DATABASE $PMADB;
#FLUSH PRIVILEGES;
#MYSQL_PMA1
#CREATE PMA USER
if [ -f '/usr/bin/mariadb' ]; then
mysql_server="mariadb"
else
mysql_server="mysql"
fi
mysql_out=$(mktemp)
$mysql -e 'SELECT VERSION()' > $mysql_out
mysql_ver=$(cat $mysql_out | tail -n1 | cut -f 1 -d -)
mysql_ver_sub=$(echo $mysql_ver | cut -d '.' -f1)
mysql_ver_sub_sub=$(echo $mysql_ver | cut -d '.' -f2)
if [ "$mysql" = "mysql" ] && [ "$mysql_ver_sub" -ge 8 ]; then
query="CREATE USER '$PMAUSER'@'localhost' IDENTIFIED BY '$PASS';"
$mysql_server -uroot -e "$query" > /dev/null
query="CREATE DATABASE $PMADB;"
$mysql_server -uroot -e "$query" > /dev/null
query="GRANT USAGE ON $PMADB.* TO '$PMAUSER'@'localhost';"
$mysql_server -uroot -e "$query" > /dev/null
query="GRANT ALL PRIVILEGES ON $PMADB.* TO '$PMAUSER'@'localhost';"
$mysql_server -uroot -e "$query" > /dev/null
query="FLUSH PRIVILEGES;"
$mysql_server -uroot -e "$query" > /dev/null
else
query="CREATE USER '$PMAUSER'@'localhost' IDENTIFIED BY '$PASS';"
$mysql_server -uroot -e "$query" > /dev/null
query="CREATE DATABASE $PMADB;"
$mysql_server -uroot -e "$query" > /dev/null
query="GRANT USAGE ON $PMADB.* TO '$PMAUSER'@'localhost' IDENTIFIED BY '$PASS';"
$mysql_server -uroot -e "$query" > /dev/null
query="GRANT ALL PRIVILEGES ON $PMADB.* TO '$PMAUSER'@'localhost';"
$mysql_server -uroot -e "$query" > /dev/null
query="FLUSH PRIVILEGES;"
$mysql_server -uroot -e "$query" > /dev/null
fi
#MYSQL DB and TABLES ADDITION
$mysql_server -uroot < "$HESTIA_INSTALL_DIR/phpmyadmin/create_tables.sql"

View File

@@ -0,0 +1,40 @@
Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/
Alias /roundcube /var/lib/roundcube
Alias /webmail /var/lib/roundcube
# Access to tinymce files
<Directory "/usr/share/tinymce/www/">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Order allow,deny
allow from all
</Directory>
<Directory /var/lib/roundcube/>
Options +FollowSymLinks
# This is needed to parse /var/lib/roundcube/.htaccess. See its
# content before setting AllowOverride to None.
AllowOverride All
order allow,deny
allow from all
</Directory>
# Protecting basic directories:
<Directory /var/lib/roundcube/config>
Options -FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/lib/roundcube/temp>
Options -FollowSymLinks
AllowOverride None
Order allow,deny
Deny from all
</Directory>
<Directory /var/lib/roundcube/logs>
Options -FollowSymLinks
AllowOverride None
Order allow,deny
Deny from all
</Directory>

View File

@@ -0,0 +1,32 @@
<?php
// Password Plugin options
// -----------------------
// A driver to use for password change. Default: "sql".
// See README file for list of supported driver names.
$config["password_driver"] = "hestia";
// Require the new password to be a certain length.
// set to blank to allow passwords of any length
$config["password_minimum_length"] = 8;
// Require the new password to contain a letter and punctuation character
// Change to false to remove this check.
$config["password_require_nonalpha"] = false;
// Enables logging of password changes into logs/password
$config["password_log"] = false;
// Comma-separated list of login exceptions for which password change
// will be not available (no Password tab in Settings)
$config["password_login_exceptions"] = null;
// By default domains in variables are using unicode.
// Enable this option to use punycoded names
$config["password_idn_ascii"] = false;
// Hestia Driver options
// -----------------------
// Control Panel host
$config["password_hestia_host"] = "localhost";
$config["password_hestia_port"] = "8083";

View File

@@ -0,0 +1,57 @@
<?php
/**
* Hestia Control Panel Password Driver
*
* @version 1.0
* @author HestiaCP <info@hestiacp.com>
*/
class rcube_hestia_password {
public function save($curpass, $passwd) {
$rcmail = rcmail::get_instance();
$hestia_host = $rcmail->config->get("password_hestia_host");
if (empty($hestia_host)) {
$hestia_host = "localhost";
}
$hestia_port = $rcmail->config->get("password_hestia_port");
if (empty($hestia_port)) {
$hestia_port = "8083";
}
$postvars = [
"email" => $_SESSION["username"],
"password" => $curpass,
"new" => $passwd,
];
$url = "https://{$hestia_host}:{$hestia_port}/reset/mail/";
$ch = curl_init();
if (
false ===
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($postvars),
CURLOPT_USERAGENT => "Hestia Control Panel Password Driver",
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
])
) {
// should never happen
throw new Exception("curl_setopt_array() failed: " . curl_error($ch));
}
$result = curl_exec($ch);
if (curl_errno($ch) !== CURLE_OK) {
throw new Exception("curl_exec() failed: " . curl_error($ch));
}
curl_close($ch);
if (strpos($result, "ok") && !strpos($result, "error")) {
return PASSWORD_SUCCESS;
} else {
return PASSWORD_ERROR;
}
}
}

View File

@@ -0,0 +1,104 @@
<?php
/* Local configuration for Roundcube Webmail */
//rewrite below this line
$config["db_dsnw"] = "mysql://roundcube:%password%@localhost/roundcube";
// Log sent messages to <log_dir>/sendmail or to syslog
$config["smtp_log"] = false;
// Log IMAP conversation to <log_dir>/imap or to syslog
$config["imap_debug"] = true;
// Log SMTP conversation to <log_dir>/smtp.log or to syslog
$config["smtp_debug"] = true;
// ----------------------------------
// IMAP
// ----------------------------------
// The IMAP host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// Enter hostname with prefix ssl:// to use Implicit TLS, or use
// prefix tls:// to use STARTTLS.
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %s - domain name after the '@' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %t = domain.tld
// WARNING: After hostname change update of mail_host column in users table is
// required to match old user data records with the new host.
$config["imap_host"] = "localhost:143";
// IMAP socket context options
// See http://php.net/manual/en/context.ssl.php
// The example below enables server certificate validation
//$config['imap_conn_options'] = array(
// 'ssl' => array(
// 'verify_peer' => true,
// 'verify_depth' => 3,
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ),
// );
// Note: These can be also specified as an array of options indexed by hostname
$config["imap_conn_options"] = [
"ssl" => [
"verify_peer" => false,
"verify_peer_name" => false,
"verify_depth" => 3,
"cafile" => "/etc/ssl/certs/ca-certificates.crt",
],
];
// SMTP socket context options
// See http://php.net/manual/en/context.ssl.php
// The example below enables server certificate validation, and
// requires 'smtp_timeout' to be non zero.
// $config['smtp_conn_options'] = array(
// 'ssl' => array(
// 'verify_peer' => true,
// 'verify_depth' => 3,
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ),
// );
// Note: These can be also specified as an array of options indexed by hostname
$config["smtp_conn_options"] = [
"ssl" => [
"verify_peer" => false,
"verify_peer_name" => false,
"verify_depth" => 3,
"cafile" => "/etc/ssl/certs/ca-certificates.crt",
],
];
// provide an URL where a user can get support for this Roundcube installation
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
$config["support_url"] = "";
// use this folder to store log files
// must be writeable for the user who runs PHP process (Apache user if mod_php is being used)
// This is used by the 'file' log driver.
$config["log_dir"] = "/var/log/roundcube/";
// This key is used for encrypting purposes, like storing of imap password
// in the session. For historical reasons it's called DES_key, but it's used
// with any configured cipher_method (see below).
// For the default cipher_method a required key length is 24 characters.
$config["des_key"] = "%des_key%";
// Maximum number of recipients per message (including To, Cc, Bcc).
// Default: 0 (no limit)
$config["max_recipients"] = 100;
// List of active plugins (in plugins/ directory)
$config["plugins"] = ["password", "newmail_notifier", "zipdownload", "archive"];
$config["default_user"] = "%u";
$config["default_pass"] = "%p";
$config["smtp_host"] = "localhost:587";
// Log session authentication errors to <log_dir>/session or to syslog
$config["log_session"] = true;

View File

@@ -0,0 +1,56 @@
<?php
/**
* Local mapping file to specify mime-types based on common file-name extensions
*
* Please note that this mapping takes precedence over the content-based mime-type detection
* and should only contain mappings which cannot be detected properly from the file contents.
*/
return [
"xls" => "application/vnd.ms-excel",
"xlm" => "application/vnd.ms-excel",
"xla" => "application/vnd.ms-excel",
"xlc" => "application/vnd.ms-excel",
"xlt" => "application/vnd.ms-excel",
"xlw" => "application/vnd.ms-excel",
"pdf" => "application/pdf",
"ppt" => "application/vnd.ms-powerpoint",
"pps" => "application/vnd.ms-powerpoint",
"pot" => "application/vnd.ms-powerpoint",
"doc" => "application/msword",
"dot" => "application/msword",
"odc" => "application/vnd.oasis.opendocument.chart",
"otc" => "application/vnd.oasis.opendocument.chart-template",
"odf" => "application/vnd.oasis.opendocument.formula",
"otf" => "application/vnd.oasis.opendocument.formula-template",
"odg" => "application/vnd.oasis.opendocument.graphics",
"otg" => "application/vnd.oasis.opendocument.graphics-template",
"odi" => "application/vnd.oasis.opendocument.image",
"oti" => "application/vnd.oasis.opendocument.image-template",
"odp" => "application/vnd.oasis.opendocument.presentation",
"otp" => "application/vnd.oasis.opendocument.presentation-template",
"ods" => "application/vnd.oasis.opendocument.spreadsheet",
"ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
"odt" => "application/vnd.oasis.opendocument.text",
"otm" => "application/vnd.oasis.opendocument.text-master",
"ott" => "application/vnd.oasis.opendocument.text-template",
"oth" => "application/vnd.oasis.opendocument.text-web",
"docm" => "application/vnd.ms-word.document.macroEnabled.12",
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"dotm" => "application/vnd.ms-word.template.macroEnabled.12",
"dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
"ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
"ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
"pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
"xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12",
"xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"xps" => "application/vnd.ms-xpsdocument",
"rar" => "application/x-rar-compressed",
"7z" => "application/x-7z-compressed",
"s7z" => "application/x-7z-compressed",
"vcf" => "text/vcard",
"ics" => "text/calendar",
];

View File

@@ -0,0 +1,126 @@
<?php
// managesieve server address, default is localhost.
// Replacement variables supported in host name:
// %h - user's IMAP hostname
// %n - http hostname ($_SERVER['SERVER_NAME'])
// %d - domain (http hostname without the first part)
// For example %n = mail.domain.tld, %d = domain.tld
$config["managesieve_host"] = "localhost:4190";
// authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL
// or none. Optional, defaults to best method supported by server.
$config["managesieve_auth_type"] = null;
// Optional managesieve authentication identifier to be used as authorization proxy.
// Authenticate as a different user but act on behalf of the logged in user.
// Works with PLAIN and DIGEST-MD5 auth.
$config["managesieve_auth_cid"] = null;
// Optional managesieve authentication password to be used for imap_auth_cid
$config["managesieve_auth_pw"] = null;
// use or not TLS for managesieve server connection
// Note: tls:// prefix in managesieve_host is also supported
$config["managesieve_usetls"] = false;
// Connection scket context options
// See http://php.net/manual/en/context.ssl.php
// The example below enables server certificate validation
//$config['managesieve_conn_options'] = array(
// 'ssl' => array(
// 'verify_peer' => true,
// 'verify_depth' => 3,
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ),
// );
// Note: These can be also specified as an array of options indexed by hostname
$config["managesieve_conn_options"] = null;
// A file with default script content (eg. spam filter)
//$config['managesieve_default'] = '/etc/dovecot/sieve/global';
$config["managesieve_default"] = "/etc/dovecot/sieve/default";
// The name of the script which will be used when there's no user script
$config["managesieve_script_name"] = "managesieve";
// Sieve RFC says that we should use UTF-8 endcoding for mailbox names,
// but some implementations does not covert UTF-8 to modified UTF-7.
// Defaults to UTF7-IMAP
$config["managesieve_mbox_encoding"] = "UTF-8";
// I need this because my dovecot (with listescape plugin) uses
// ':' delimiter, but creates folders with dot delimiter
$config["managesieve_replace_delimiter"] = "";
// disabled sieve extensions (body, copy, date, editheader, encoded-character,
// envelope, environment, ereject, fileinto, ihave, imap4flags, index,
// mailbox, mboxmetadata, regex, reject, relational, servermetadata,
// spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc.
// Note: not all extensions are implemented
$config["managesieve_disabled_extensions"] = [];
// Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve
$config["managesieve_debug"] = false;
// Enables features described in http://wiki.kolab.org/KEP:14
$config["managesieve_kolab_master"] = false;
// Script name extension used for scripts including. Dovecot uses '.sieve',
// Cyrus uses '.siv'. Doesn't matter if you have managesieve_kolab_master disabled.
$config["managesieve_filename_extension"] = ".sieve";
// List of reserved script names (without extension).
// Scripts listed here will be not presented to the user.
$config["managesieve_filename_exceptions"] = [];
// List of domains limiting destination emails in redirect action
// If not empty, user will need to select domain from a list
$config["managesieve_domains"] = [];
// Default list of entries in header selector
$config["managesieve_default_headers"] = ["Subject", "From", "To"];
// Enables separate management interface for vacation responses (out-of-office)
// 0 - no separate section (default),
// 1 - add Vacation section,
// 2 - add Vacation section, but hide Filters section
$config["managesieve_vacation"] = 0;
// Enables separate management interface for setting forwards (redirect to and copy to)
// 0 - no separate section (default),
// 1 - add Forward section,
// 2 - add Forward section, but hide Filters section
$config["managesieve_forward"] = 0;
// Default vacation interval (in days).
// Note: If server supports vacation-seconds extension it is possible
// to define interval in seconds here (as a string), e.g. "3600s".
$config["managesieve_vacation_interval"] = 0;
// Some servers require vacation :addresses to be filled with all
// user addresses (aliases). This option enables automatic filling
// of these on initial vacation form creation.
$config["managesieve_vacation_addresses_init"] = false;
// Sometimes you want to always reply with mail email address
// This option enables automatic filling of :from field on initial vacation form creation.
$config["managesieve_vacation_from_init"] = false;
// Supported methods of notify extension. Default: 'mailto'
$config["managesieve_notify_methods"] = ["mailto"];
// Enables scripts RAW editor feature
$config["managesieve_raw_editor"] = true;
// Disabled actions
// Prevent user from performing specific actions:
// list_sets, enable_disable_set, delete_set, new_set, download_set, new_rule, delete_rule
// Note: disabling list_sets removes the Filter sets widget from the UI and means
// the set defined in managesieve_script_name will always be used (and activated)
$config["managesieve_disabled_actions"] = [];
// List of hosts that support managesieve.
// Activate managesieve for selected hosts only. If this is not set all hosts are allowed.
// Example: $config['managesieve_allowed_hosts'] = array('host1.mydomain.com','host2.mydomain.com');
$config["managesieve_allowed_hosts"] = null;

View File

@@ -0,0 +1,15 @@
<?php
// Enables basic notification
$config["newmail_notifier_basic"] = true;
// Enables sound notification
$config["newmail_notifier_sound"] = false;
// Enables desktop notification
$config["newmail_notifier_desktop"] = false;
// Desktop notification close timeout in seconds
$config["newmail_notifier_desktop_timeout"] = 5;
?>

View File

@@ -0,0 +1,21 @@
<?php
/**
* ZipDownload configuration file
*/
// Zip attachments
// Only show the link when there are more than this many attachments
// -1 to prevent downloading of attachments as zip
$config["zipdownload_attachments"] = 1;
// Zip selection of mail messages
// This option enables downloading of multiple messages as one zip archive.
// The number or string value specifies maximum total size of all messages
// in the archive (not the size of the archive itself).
$config["zipdownload_selection"] = "100MB";
// Charset to use for filenames inside the zip
$config["zipdownload_charset"] = "ISO-8859-1";
?>

View File

@@ -0,0 +1,73 @@
<?php
$_ENV["SNAPPYMAIL_INCLUDE_AS_API"] = true;
require_once "/var/lib/snappymail/index.php";
$oConfig = \RainLoop\Api::Config();
// Change default login data / key
$oConfig->Set("security", "admin_login", $argv[1]);
$oConfig->Set("security", "admin_panel_key", $argv[1]);
$oConfig->SetPassword($argv[2]);
// Allow Contacts to be saved in database
$oConfig->Set("contacts", "enable", "On");
$oConfig->Set("contacts", "allow_sync", "On");
$oConfig->Set("contacts", "type", "mysql");
$oConfig->Set("contacts", "pdo_dsn", "mysql:host=127.0.0.1;port=3306;dbname=snappymail");
$oConfig->Set("contacts", "pdo_user", "snappymail");
$oConfig->Set("contacts", "pdo_password", $argv[3]);
// Plugins
$oConfig->Set("plugins", "enable", "On");
\SnappyMail\Repository::installPackage("plugin", "change-password");
\SnappyMail\Repository::installPackage("plugin", "change-password-hestia");
$sFile = APP_PRIVATE_DATA . "configs/plugin-change-password.json";
if (!file_exists($sFile)) {
file_put_contents(
"$sFile",
json_encode(
[
"plugin" => [
"pass_min_length" => 8,
"pass_min_strength" => 60,
"driver_hestia_enabled" => true,
"driver_hestia_allowed_emails" => "*",
"hestia_host" => gethostname(),
"hestia_port" => $argv[4], // $BACKEND_PORT
],
],
JSON_PRETTY_PRINT,
),
);
}
\SnappyMail\Repository::enablePackage("change-password");
\SnappyMail\Repository::installPackage("plugin", "add-x-originating-ip-header");
\SnappyMail\Repository::enablePackage("add-x-originating-ip-header");
$sFile = APP_PRIVATE_DATA . "configs/plugin-add-x-originating-ip-header.json";
if (!file_exists($sFile)) {
file_put_contents(
"$sFile",
json_encode(
[
"plugin" => [
"check_proxy" => true,
],
],
JSON_PRETTY_PRINT,
),
);
}
$oConfig->Save();
$sFile = APP_PRIVATE_DATA . "domains/hestia.json";
if (!file_exists($sFile)) {
$config = json_decode(APP_PRIVATE_DATA . "domains/default.json", true);
$config["IMAP"]["shortLogin"] = true;
$config["SMTP"]["shortLogin"] = true;
file_put_contents($sFile, json_encode($config, JSON_PRETTY_PRINT));
}

View File

@@ -0,0 +1,12 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='ns1.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='ns2.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='ns1' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='ns2' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='mail' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='webmail' TYPE='CNAME' PRIORITY='' VALUE='mail.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='@' TYPE='MX' PRIORITY='0' VALUE='mail.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='@' TYPE='TXT' PRIORITY='' VALUE='"v=spf1 a mx ip4:%ip% -all"' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='12' RECORD='_dmarc' TYPE='TXT' PRIORITY='' VALUE='"v=DMARC1; p=quarantine; pct=100"' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,11 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns1%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns2%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns3%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns4%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns5%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns6%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns7%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns8%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,16 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns1%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns2%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns3%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns4%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns5%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns6%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns7%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns8%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='12' RECORD='mail' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='13' RECORD='webmail' TYPE='CNAME' PRIORITY='' VALUE='mail.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='14' RECORD='@' TYPE='MX' PRIORITY='0' VALUE='mail.%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='15' RECORD='@' TYPE='TXT' PRIORITY='' VALUE='"v=spf1 a mx ip4:%ip% -all"' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='16' RECORD='_dmarc' TYPE='TXT' PRIORITY='' VALUE='"v=DMARC1; p=quarantine; pct=100"' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,17 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns1%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns2%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns3%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns4%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns5%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns6%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns7%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns8%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='12' RECORD='@' TYPE='MX' PRIORITY='1' VALUE='ASPMX.L.GOOGLE.COM.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='13' RECORD='@' TYPE='MX' PRIORITY='5' VALUE='ALT1.ASPMX.L.GOOGLE.COM.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='14' RECORD='@' TYPE='MX' PRIORITY='5' VALUE='ALT2.ASPMX.L.GOOGLE.COM.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='15' RECORD='@' TYPE='MX' PRIORITY='10' VALUE='ALT3.ASPMX.L.GOOGLE.COM.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='16' RECORD='@' TYPE='MX' PRIORITY='10' VALUE='ALT4.ASPMX.L.GOOGLE.COM.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='17' RECORD='@' TYPE='TXT' PRIORITY='' VALUE='"v=spf1 a mx ip4:%ip% include:_spf.google.com -all"' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,22 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns1%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns2%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns3%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns4%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns5%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns6%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns7%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns8%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='12' RECORD='@' TYPE='TXT' PRIORITY='' VALUE='"v=spf1 a mx ip4:%ip% include:spf.protection.outlook.com -all"' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='13' RECORD='_dmarc' TYPE='TXT' PRIORITY='' VALUE='v=DMARC1; p=none; pct=100; fo=1'
ID='14' RECORD='autodiscover' TYPE='CNAME' PRIORITY='' VALUE='autodiscover.outlook.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='15' RECORD='lyncdiscover' TYPE='CNAME' PRIORITY='' VALUE='webdir.online.lync.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='16' RECORD='sip' TYPE='CNAME' PRIORITY='' VALUE='sipdir.online.lync.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='17' RECORD='enterpriseregistration' TYPE='CNAME' PRIORITY='' VALUE='enterpriseregistration.windows.net.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='18' RECORD='enterpriseenrollment' TYPE='CNAME' PRIORITY='' VALUE='enterpriseenrollment.manage.microsoft.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='19' RECORD='_sip._tls' TYPE='SRV' PRIORITY='100' VALUE='1 443 sipdir.online.lync.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='20' RECORD='_sipfederationtls._tcp' TYPE='SRV' PRIORITY='100' VALUE='1 5061 sipfed.online.lync.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='21' RECORD='login' TYPE='CNAME' PRIORITY='' VALUE='login.microsoftonline.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='22' RECORD='mail' TYPE='CNAME' PRIORITY='' VALUE='mail.office365.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,15 @@
ID='1' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns1%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='2' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns2%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='3' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns3%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='4' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns4%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='5' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns5%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='6' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns6%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='7' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns7%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='8' RECORD='@' TYPE='NS' PRIORITY='' VALUE='%ns8%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='9' RECORD='@' TYPE='A' PRIORITY='' VALUE='%ip%' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='10' RECORD='ftp' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='11' RECORD='www' TYPE='CNAME' PRIORITY='' VALUE='%domain%.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='12' RECORD='@' TYPE='MX' PRIORITY='10' VALUE='mx.zoho.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='13' RECORD='@' TYPE='MX' PRIORITY='20' VALUE='mx2.zoho.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='14' RECORD='@' TYPE='MX' PRIORITY='50' VALUE='mx3.zoho.com.' SUSPENDED='no' TIME='%time%' DATE='%date%'
ID='15' RECORD='@' TYPE='TXT' PRIORITY='' VALUE='"v=spf1 a mx ip4:%ip% include:zoho.com -all"' SUSPENDED='no' TIME='%time%' DATE='%date%'

View File

@@ -0,0 +1,12 @@
Hello {{name}},
Your account has been created and ready to use.
https://{{hostname}}/login/
Username: {{user}}
Password: {{password}}
Best regards,
--
{{appname}}

View File

@@ -0,0 +1,11 @@
Database has been created.
Database: {{database}}
Username: {{username}}
Password: {{password}}
SQL Manager: {{dbadmin}}
Best regards,
--
{{appname}}

View File

@@ -0,0 +1,30 @@
Mail account has been created.
Common Account Settings:
Username: {{account}}@{{domain}}
Password: {{password}}
Webmail: {{webmail}}
Hostname: {{hostname}}
IMAP Settings
Authentication: Normal password
SSL/TLS: Port 993
STARTTLS: Port 143
No encryption: Port 143
POP3 Settings
Authentication: Normal password
SSL/TLS: Port 995
STARTTLS: Port 110
No encryption: Port 110
SMTP Settings
Authentication: Normal password
SSL/TLS: Port 465
STARTTLS: Port 587
No encryption: Port 25
Best regards,
--
{{appname}}

View File

@@ -0,0 +1,10 @@
FTP account has been created and ready to use.
Hostname: {{domain}}
Username: {{username}}
Password: {{password}}
Best regards,
--
{{appname}}

View File

@@ -0,0 +1,15 @@
<subject>{{hostname}} Password reset at {{date}}</subject>
Hello {{name}},
To reset your {{appname}} password, please follow this link:
https://{{hostname}}/reset/?action=confirm&user={{user}}&code={{resetcode}}
Alternatively, you may go to https://{{hostname}}/reset/?action=code&user={{user}} and enter the following reset code:
{{resetcode}}
If you did not request password reset, please ignore this message and accept our apologies.
Best regards,
--
{{appname}}

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Access Denied</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="error icon-large fa-times-circle"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">Access Denied</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>You do not have permission to view this page.</p>
<p>Please check your credentials and try again.</p>
<section class="footer"><strong>Error Code:</strong> 403</section>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Page Not Found</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="info icon-large fa-question-circle"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zM262.655 90c-54.497 0-89.255 22.957-116.549 63.758-3.536 5.286-2.353 12.415 2.715 16.258l34.699 26.31c5.205 3.947 12.621 3.008 16.665-2.122 17.864-22.658 30.113-35.797 57.303-35.797 20.429 0 45.698 13.148 45.698 32.958 0 14.976-12.363 22.667-32.534 33.976C247.128 238.528 216 254.941 216 296v4c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-1.333c0-28.462 83.186-29.647 83.186-106.667 0-58.002-60.165-102-116.531-102zM256 338c-25.365 0-46 20.635-46 46 0 25.364 20.635 46 46 46s46-20.636 46-46c0-25.365-20.635-46-46-46z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">Page Not Found</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>Oops! We couldn't find the page that you're looking for.</p>
<p>Please check the address and try again.</p>
<section class="footer"><strong>Error Code:</strong> 404</section>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Resource is Gone</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="info icon-large fa-sign-out-alt"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M272 112v51.6h-96c-26.5 0-48 21.5-48 48v88.6c0 26.5 21.5 48 48 48h96v51.6c0 42.6 51.7 64.2 81.9 33.9l144-143.9c18.7-18.7 18.7-49.1 0-67.9l-144-144C323.8 48 272 69.3 272 112zm192 144L320 400v-99.7H176v-88.6h144V112l144 144zM96 64h84c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H96c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h84c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H96c-53 0-96-43-96-96V160c0-53 43-96 96-96z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">Resource is Gone</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>Oops! The requested resource is no longer available.</p>
<p>Please check the address and try again.</p>
<section class="footer"><strong>Error Code:</strong> 410</section>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Internal Server Error</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="warning icon-large fa-exclamation-triangle"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 576 512"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">Internal Server Error</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>Oops! Something went wrong.</p>
<p>
The server encountered an internal error or misconfiguration and was unable to
complete your request.
</p>
<section class="footer"><strong>Error Code:</strong> 500</section>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Coming Soon</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="warning icon-large fa-hard-hat"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M480 288c0-80.25-49.28-148.92-119.19-177.62L320 192V80a16 16 0 0 0-16-16h-96a16 16 0 0 0-16 16v112l-40.81-81.62C81.28 139.08 32 207.75 32 288v64h448zm16 96H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h480a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">We're working on it!</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>This site is currently under construction.</p>
<p>Please check back soon.</p>
<section class="footer"><strong>Domain:</strong> %domain%</section>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,3 @@
# hestiacp autogenerated robots.txt
User-agent: *
Crawl-delay: 10

View File

@@ -0,0 +1,2 @@
ErrorDocument 403 /index.html
ErrorDocument 404 /index.html

View File

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Access Denied</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<svg
class="error icon-large fa-exclamation-circle"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
></path>
</svg>
</div>
<h1 class="animate__animated animate__fadeIn">This site is currently suspended</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>If you are the owner of this site, please contact support for more information.</p>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Success!</title>
<style>
body {
background-color: #f5f5f5;
margin-top: 8%;
color: #5d5d5d;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-align: center;
}
h1 {
font-size: 2.45em;
font-weight: 700;
color: #5d5d5d;
letter-spacing: -0.02em;
margin-bottom: 30px;
margin-top: 30px;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
}
.animate__animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate__fadeIn {
animation-name: fadeIn;
}
.info {
color: #5594cf;
fill: #5594cf;
}
.error {
color: #c92127;
fill: #c92127;
}
.warning {
color: #ffcc33;
fill: #ffcc33;
}
.success {
color: #5aba47;
fill: #5aba47;
}
.icon-large {
height: 132px;
width: 132px;
}
.description-text {
color: #707070;
letter-spacing: -0.01em;
font-size: 1.25em;
line-height: 20px;
}
.footer {
margin-top: 40px;
font-size: 0.7em;
}
.animate__delay-1s {
animation-delay: 1s;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="animate__animated animate__fadeIn">
<i class="success">
<svg
class="success icon-large fa-check-circle"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
>
<path
d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"
></path>
</svg>
</i>
</div>
<h1 class="animate__animated animate__fadeIn">Success!</h1>
<div class="description-text animate__animated animate__fadeIn animate__delay-1s">
<p>Your new web server is ready to use.</p>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,96 @@
# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf.d
# | `-- *
# Global configuration
PidFile ${APACHE_PID_FILE}
Timeout 30
KeepAlive Off
MaxKeepAliveRequests 100
KeepAliveTimeout 10
<IfModule mpm_prefork_module>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxClients 200
MaxRequestsPerChild 4000
</IfModule>
<IfModule mpm_worker_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 200
MaxRequestsPerChild 4000
</IfModule>
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxClients 200
MaxRequestsPerChild 4000
</IfModule>
# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
#User www-data
#Group www-data
AccessFileName .htaccess
<Files ~ "^\.ht">
Order allow,deny
Deny from all
Satisfy all
</Files>
DefaultType None
HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
# Include module configuration:
Include mods-enabled/*.load
Include mods-enabled/*.conf
# Include list of ports to listen on and which to use for name based vhosts
Include ports.conf
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
LogFormat "%b" bytes
IncludeOptional conf.d/*.conf
IncludeOptional conf.d/domains/webmail.*.conf
IncludeOptional conf.d/domains/*.conf
# Include the virtual host configurations:
#Include sites-enabled/
ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 500 /error/50x.html
ErrorDocument 501 /error/50x.html
ErrorDocument 502 /error/50x.html
ErrorDocument 503 /error/50x.html
ErrorDocument 506 /error/50x.html

View File

@@ -0,0 +1,5 @@
<IfModule mpm_event_module>
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
</IfModule>

View File

@@ -0,0 +1,7 @@
Listen 127.0.0.1:8081
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>

View File

@@ -0,0 +1,18 @@
<VirtualHost directIP:directPORT>
ServerName directIP
DocumentRoot /var/www/html/
Alias /error/ /var/www/document_errors/
</VirtualHost>
<VirtualHost directIP:directSSLPORT>
ServerName directIP
DocumentRoot /var/www/html/
Alias /error/ /var/www/document_errors/
SSLEngine on
SSLVerifyClient none
SSLCertificateFile /usr/local/hestia/ssl/certificate.crt
SSLCertificateKeyFile /usr/local/hestia/ssl/certificate.key
</VirtualHost>

View File

@@ -0,0 +1,12 @@
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";

View File

@@ -0,0 +1,24 @@
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
auth-nxdomain no;
allow-recursion { 127.0.0.1; ::1; };
allow-transfer {"none";};
hostname none;
server-id none;
version none;
};

View File

@@ -0,0 +1,88 @@
#Automatically Generated by clamav-daemon postinst
#To reconfigure clamd run #dpkg-reconfigure clamav-daemon
#Please read /usr/share/doc/clamav-daemon/README.Debian.gz for details
LocalSocket /run/clamav/clamd.ctl
FixStaleSocket true
LocalSocketGroup clamav
LocalSocketMode 666
# TemporaryDirectory is not set to its default /tmp here to make overriding
# the default with environment variables TMPDIR/TMP/TEMP possible
User clamav
ScanMail true
ScanArchive true
ArchiveBlockEncrypted false
MaxDirectoryRecursion 15
FollowDirectorySymlinks false
FollowFileSymlinks false
ReadTimeout 180
MaxThreads 12
MaxConnectionQueueLength 15
LogSyslog false
LogRotate true
LogFacility LOG_LOCAL6
LogClean false
LogVerbose true
PreludeEnable no
PreludeAnalyzerName ClamAV
DatabaseDirectory /var/lib/clamav
OfficialDatabaseOnly false
SelfCheck 3600
Foreground false
Debug false
ScanPE true
MaxEmbeddedPE 10M
ScanOLE2 true
ScanPDF true
ScanHTML true
MaxHTMLNormalize 10M
MaxHTMLNoTags 2M
MaxScriptNormalize 5M
MaxZipTypeRcg 1M
ScanSWF true
ExitOnOOM false
LeaveTemporaryFiles false
AlgorithmicDetection true
ScanELF true
IdleTimeout 30
CrossFilesystems true
PhishingSignatures true
PhishingScanURLs true
PhishingAlwaysBlockSSLMismatch false
PhishingAlwaysBlockCloak false
PartitionIntersection false
DetectPUA false
ScanPartialMessages false
HeuristicScanPrecedence false
StructuredDataDetection false
CommandReadTimeout 5
SendBufTimeout 200
MaxQueue 100
ExtendedDetectionInfo true
OLE2BlockMacros false
AllowAllMatchScan true
ForceToDisk false
DisableCertCheck false
DisableCache false
MaxScanTime 120000
MaxScanSize 100M
MaxFileSize 25M
MaxRecursion 16
MaxFiles 10000
MaxPartitions 50
MaxIconsPE 100
PCREMatchLimit 10000
PCRERecMatchLimit 5000
PCREMaxFileSize 25M
ScanXMLDOCS true
ScanHWP3 true
MaxRecHWP3 16
StreamMaxLength 25M
LogFile /var/log/clamav/clamav.log
LogTime true
LogFileUnlock false
LogFileMaxSize 0
Bytecode true
BytecodeSecurity TrustSigned
BytecodeTimeout 60000
PidFile /run/clamav/clamd.pid
OnAccessMaxFileSize 5M

View File

@@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
mQENBFJIGbEBCAC8SHOOFo7iDTbnC2GhNZ+uBGCh226Dn1QPoFZNFM/DNakHZ6rD
G3wzr8++eKz4fJual/VLllE2N9XDPuxbozb3LLkcyY1WzJqtIXbXhFGQ/SuIeT+x
QY90XU6t2Ckze2c+zUniAWmJ8GSyVmXOoc9JxAQ1u47wvGXLzrjWXc8u8PNRYXuf
fZplTL+dFu9P0d6lP8FGsV+r9wXvvazpRTz3+H8PKrGCYT55ZQIEdG9Jgamylto2
oVPFXkwGML+TLw6oeCIBuz2y2vtivphW4MJ3ifQjDj7k3n+DTIxfDFs8lB6VRhhY
2nMHCrcZC6U2mhmXmr6O4s1fu6irBVx05ejPABEBAAG0IFNlcmdoZXkgUm9kaW4g
PHNraWRAdmVzdGFjcC5jb20+iQE4BBMBAgAiBQJSSBmxAhsDBgsJCAcDAgYVCAIJ
CgsEFgIDAQIeAQIXgAAKCRBCxbITCh93FPdqB/93GjV9g+wBfeZYLHQK9MDU2wBb
VloYOJJae6IvYKYQVAJayD3PbHdpxrF8s9e23vdnmb9jKu6jX6oV54EIyqP2HPiN
QYc8wcea+eSHerznBixCtoQh8mtdWGFeN71zU/ig7L5qlOVF/EmxDVZTFUeivFxh
IV6qyBnktQKktE45585yKZyyLtfGoXA54DGK69OtJFh+wdkKEMmUXocMl7wUrxW6
Cx2CuKeEXEgvwu8mRHQi3S3T9XP456qWEn5dWyMVcP660IzEuZfSJApZusNK7zG3
WMy0/EuX7xHNY3mcNxTOUN1LsO7iHnhHD9+iKWJo9parGkMZzc92MpjDK/g7uQEN
BFJIGbEBCAC7k5QEA9WQM7E3ceNaeLMrA9lXfuzaNCcySq7ONdVAa5PxzbSKdHvz
QFoL1VFqBTYQ038lbil1XqnoM0zvIfAI3LcpS8sq92El/vPxp6jZh2Ari9Uw7x95
k2cZMgI67g+zQMGdjVRA155nFQRCgg000xU4F7JA6+WsuLlVUmccsDv7YWJExMtC
YPxiuz5DFu8RALnw4Ckts+dbwsrcvUHhkm9b6RAsdCKjjRpUZjLgdltjH83gUVvt
i1YmdjjsVpt95dtsaG+ad852g/Rk8EdxNMkjPF6HLA67CLADP9wYaj80yPcPtylS
ycvPtcclVeHkFBRVM8xZpQd4iD19MWI1ABEBAAGJAR8EGAECAAkFAlJIGbECGwwA
CgkQQsWyEwofdxQ7tQgAhB0FwTs7L8Qr63DHC2yAnXVxgtTAY1/36CccNXVculyR
+EkLcwahms9AKhz7eQb+Mud+5vH0GRohLp2npgO38CjVUfIP5d+Y6dsthmrkF6p8
XdV1dVK9vWX+i/YZSw/Mded30Cq4P2Yhq9EaemMT0rtli8lz2NnkZ9dFJZk1lzJC
CZmRpbjSNWqRU4f7qyh21lYk/OC/0XE8fh8CaO23TZ+6gBionoCztwb7NyC9OArN
qYlNnbmh9iNqdblykPS3bkjf34n2xyMgnIehNrM89tk8PY4UfNPhgT1TMD9W3Svq
ynNZvLuF/FIDwDeC1qcfjGbfDn9fXO/lMIIRooQYKQ==
=J2HJ
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -0,0 +1,2 @@
bl.spamcop.net
zen.spamhaus.org

View File

@@ -0,0 +1,476 @@
######################################################################
# #
# Exim configuration file for Hestia Control Panel #
# #
######################################################################
#SPAMASSASSIN = yes
#SPAM_SCORE = 50
#SPAM_REJECT_SCORE = 100
#CLAMD = yes
smtp_banner = $smtp_active_hostname
smtp_active_hostname = ${lookup dnsdb{>: defer_never,ptr=$interface_address}{${listextract{1}{$value}}}{$primary_hostname}}
add_environment = <; PATH=/bin:/usr/bin
keep_environment =
disable_ipv6 = true
smtputf8_advertise_hosts =
domainlist local_domains = dsearch;/etc/exim4/domains/
domainlist relay_to_domains = dsearch;/etc/exim4/domains/
hostlist relay_from_hosts = 127.0.0.1
hostlist whitelist = net-iplsearch;/etc/exim4/white-blocks.conf
hostlist spammers = net-iplsearch;/etc/exim4/spam-blocks.conf
no_local_from_check
untrusted_set_sender = *
acl_smtp_connect = acl_check_spammers
acl_smtp_mail = acl_check_mail
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
acl_smtp_mime = acl_check_mime
.ifdef SPAMASSASSIN
spamd_address = 127.0.0.1 783
.endif
.ifdef CLAMD
av_scanner = clamd: /run/clamav/clamd.ctl
.endif
log_selector = +tls_sni
tls_advertise_hosts = *
# We test that $tls_in_sni is a valid domain, by an arbitrary email address foo@domain.tld .
# Then, we extract the domain with a function that would fail if the email address is invalid.
# If the certificate exists, we will use it, otherwise the default certificate in /etc/ssl will be used.
tls_certificate = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.crt} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.crt}\
{/usr/local/hestia/ssl/certificate.crt}\
}
tls_privatekey = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.key} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.key}\
{/usr/local/hestia/ssl/certificate.key}\
}
daemon_smtp_ports = 25 : 465 : 587
tls_on_connect_ports = 465
tls_require_ciphers = PERFORMANCE:-RSA:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3:%SERVER_PRECEDENCE
never_users = root
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 0s
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim4/domains/${lookup{${lc:${domain:$h_from:}}}dsearch{/etc/exim4/domains/}}/dkim.pem
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
OUTGOING_IP = /etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/ip
SMTP_RELAY_FILE = ${if exists{/etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/smtp_relay.conf}{/etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/smtp_relay.conf}{/etc/exim4/smtp_relay.conf}}
SMTP_RELAY_HOST = ${lookup{host}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PORT = ${lookup{port}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_USER = ${lookup{user}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PASS = ${lookup{pass}lsearch{SMTP_RELAY_FILE}}
# Custom Filter
system_filter = /etc/exim4/system.filter
system_filter_user = Debian-exim
######################################################################
# ACL CONFIGURATION #
# Specifies access control lists for incoming SMTP mail #
######################################################################
acl_not_smtp = acl_not_smtp
begin acl
# Limit per user for PHP scripts
acl_not_smtp:
deny message = Website of user $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
ratelimit = 200 / 1h / $authenticated_id
warn ratelimit = 100 / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / account / $authenticated_id / $sender_rate / $sender_rate_period
accept
acl_check_spammers:
accept hosts = +whitelist
drop message = Your host in blacklist on this server.
log_message = Host in blacklist
hosts = +spammers
accept
acl_check_mail:
deny condition = ${if eq{$sender_helo_name}{}}
message = HELO required before MAIL
drop !authenticated = *
message = Helo name contains an IP address (HELO was $sender_helo_name) and not is valid
condition = ${if match{$sender_helo_name}{\N((\d{1,3}[.-]\d{1,3}[.-]\d{1,3}[.-]\d{1,3})|([0-9a-f]{8})|([0-9A-F]{8}))\N}{yes}{no}}
condition = ${if match {${lookup dnsdb{>: defer_never,ptr=$sender_host_address}}\}{$sender_helo_name}{no}{yes}}
delay = 45s
drop !authenticated = *
condition = ${if isip{$sender_helo_name}}
message = Access denied - Invalid HELO name (See RFC2821 4.1.3)
drop !authenticated = *
condition = ${if eq{[$interface_address]}{$sender_helo_name}}
message = $interface_address is _my_ address
accept
acl_check_rcpt:
accept hosts = :
# Limit per email account for SMTP auhenticated users
deny message = Email account $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
set acl_c_msg_limit = ${if exists{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{${lookup {$authenticated_id} lsearch{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{$value}{${readfile{/etc/exim4/limit.conf}}}}}{${readfile{/etc/exim4/limit.conf}}} }
ratelimit = $acl_c_msg_limit / 1h / strict/ $authenticated_id
warn ratelimit = ${eval:$acl_c_msg_limit / 2} / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / email / $authenticated_id / $sender_rate / $sender_rate_period
deny message = Restricted characters in address
domains = +local_domains
local_parts = ^[.] : ^.*[@%!/|]
deny message = Restricted characters in address
domains = !+local_domains
local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
require verify = sender
accept hosts = +relay_from_hosts
control = submission
accept authenticated = *
control = submission/domain=
deny message = Rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
hosts = !+whitelist
dnslists = ${readfile {/etc/exim4/dnsbl.conf}{:}}
require message = relay not permitted
domains = +local_domains : +relay_to_domains
deny message = smtp auth required
sender_domains = +local_domains
!authenticated = *
require verify = recipient
.ifdef CLAMD
warn set acl_m0 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antivirus}{yes}{no}}
set acl_m0 = yes
.endif
.ifdef SPAMASSASSIN
warn set acl_m1 = no
set acl_m3 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antispam}{yes}{no}}
set acl_m1 = yes
warn condition = ${if exists {/etc/exim4/domains/$domain/reject_spam}{yes}{no}}
set acl_m3 = yes
.endif
accept
acl_check_data:
.ifdef CLAMD
deny message = Message contains a virus ($malware_name) and has been rejected
malware = */defer_ok
condition = ${if eq{$acl_m0}{yes}{yes}{no}}
.endif
.ifdef SPAMASSASSIN
warn !authenticated = *
hosts = !+relay_from_hosts
condition = ${if < {$message_size}{1024K}}
condition = ${if eq{$acl_m1}{yes}{yes}{no}}
spam = debian-spamd:true/defer_ok
add_header = X-Spam-Score: $spam_score_int
add_header = X-Spam-Bar: $spam_bar
add_header = X-Spam-Report: $spam_report
set acl_m2 = $spam_score_int
warn condition = ${if !eq{$acl_m2}{} {yes}{no}}
condition = ${if >{$acl_m2}{SPAM_SCORE} {yes}{no}}
add_header = X-Spam-Status: Yes
message = SpamAssassin detected spam (from $sender_address to $recipients).
# Deny spam at high score if spam score > SPAM_REJECT_SCORE and delete_spam is enabled
deny message = This message scored $spam_score spam points
spam = debian-spamd:true
condition = ${if eq{$acl_m3}{yes}{yes}{no}}
condition = ${if >{$spam_score_int}{SPAM_REJECT_SCORE}{1}{0}}
.endif
accept
acl_check_mime:
deny message = Blacklisted file extension detected
condition = ${if match {${lc:$mime_filename}}{\N(\.ace|\.ade|\.adp|\.app|\.arj|\.asp|\.aspx|\.asx|\.bas|\.bat|\.cab|\.cer|\.chm|\.cmd|\.cnt|\.com|\.cpl|\.crt|\.csh|\.der|\.diagcab|\.dll|\.efi|\.exe|\.fla|\.fon|\.fxp|\.gadget|\.grp|\.hlp|\.hpj|\.hta|\.htc|\.img|\.inf|\.ins|\.iso|\.isp|\.its|\.jar|\.jnlp|\.js|\.jse|\.ksh|\.lib|\.lnk|\.mad|\.maf|\.mag|\.mam|\.maq|\.mar|\.mas|\.mat|\.mau|\.mav|\.maw|\.mcf|\.mda|\.mdb|\.mde|\.mdt|\.mdw|\.mdz|\.msc|\.msh|\.msh1|\.msh1xml|\.msh2|\.msh2xml|\.mshxml|\.msi|\.msp|\.mst|\.msu|\.ops|\.osd|\.pcd|\.pif|\.pl|\.plg|\.prf|\.prg|\.printerexport|\.ps1|\.ps1xml|\.ps2|\.ps2xml|\.psc1|\.psc2|\.psd1|\.psdm1|\.pst|\.py|\.pyc|\.pyo|\.pyw|\.pyz|\.pyzw|\.reg|\.scf|\.scr|\.sct|\.sfx|\.shb|\.shs|\.swf|\.sys|\.theme|\.tmp|\.ttf|\.url|\.vb|\.vba|\.vbe|\.vbp|\.vbs|\.vhd|\.vhdx|\.vsmacros|\.vsw|\.vxd|\.webpnp|\.website|\.wim|\.ws|\.wsc|\.wsf|\.wsh|\.xbap|\.xll|\.xnk)$\N}{1}{0}}
accept
######################################################################
# AUTHENTICATION CONFIGURATION #
######################################################################
begin authenticators
smtp_relay_login:
driver = plaintext
public_name = LOGIN
hide client_send = : SMTP_RELAY_USER : SMTP_RELAY_PASS
dovecot_plain:
driver = dovecot
public_name = PLAIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
dovecot_login:
driver = dovecot
public_name = LOGIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
######################################################################
# ROUTERS CONFIGURATION #
# Specifies how addresses are handled #
######################################################################
begin routers
send_via_unauthenticated_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
condition = ${if eq{SMTP_RELAY_USER}{}}
transport = remote_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
send_via_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
transport = smtp_relay_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
dnslookup:
driver = dnslookup
domains = !+local_domains
transport = remote_smtp
no_more
userforward:
driver = redirect
check_local_user
file = $home/.forward
require_files = ${local_part}:+${home}/.forward
domains = +local_domains
allow_filter
no_verify
no_expn
check_ancestor
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
procmail:
driver = accept
check_local_user
require_files = ${local_part}:+${home}/.procmailrc:/usr/bin/procmail
transport = procmail
no_verify
autoreplay:
driver = accept
require_files = /etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${local_part}.msg
condition = ${if exists{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${local_part}.msg}{yes}{no}}
retry_use_local_part
transport = userautoreply
unseen
aliases:
driver = redirect
headers_add = X-redirected: yes
data = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}}}}
require_files = /etc/exim4/domains/$domain/aliases
redirect_router = dnslookup
pipe_transport = address_pipe
unseen
localuser_fwd_only:
driver = accept
transport = devnull
condition = ${if exists{/etc/exim4/domains/$domain/fwd_only}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/fwd_only}{true}{false}}}}
localuser_spam:
driver = accept
transport = local_spam_delivery
condition = ${if eq {${if match{$h_X-Spam-Status:}{\N^Yes\N}{yes}{no}}} {${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}{yes}{no_such_user}}}}
localuser:
driver = accept
transport = local_delivery
condition = ${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}{true}{false}}
catchall:
driver = redirect
headers_add = X-redirected: yes
require_files = /etc/exim4/domains/$domain/aliases
data = ${extract{1}{:}{${lookup{*@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}}}}
file_transport = local_delivery
redirect_router = dnslookup
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}{false}{true}}
terminate_alias:
driver = accept
transport = devnull
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}{true}{false}}
######################################################################
# TRANSPORTS CONFIGURATION #
######################################################################
begin transports
smtp_relay_smtp:
driver = smtp
hosts_require_auth = $host_address
hosts_require_tls = $host_address
remote_smtp:
driver = smtp
helo_data = ${lookup dnsdb{>: defer_never,ptr=$sending_ip_address}{${listextract{1}{$value}}}{$primary_hostname}}
dkim_domain = DKIM_DOMAIN
dkim_selector = mail
dkim_private_key = DKIM_PRIVATE_KEY
dkim_canon = relaxed
dkim_strict = 0
hosts_try_fastopen = !*.l.google.com
interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}
procmail:
driver = pipe
command = "/usr/bin/procmail -d $local_part"
return_path_add
delivery_date_add
envelope_to_add
user = $local_part
initgroups
return_output
local_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M
quota_warn_threshold = 75%
local_spam_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}/.Spam"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M
quota_directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}"
quota_warn_threshold = 75%
address_pipe:
driver = pipe
return_output
address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add
address_reply:
driver = autoreply
userautoreply:
driver = autoreply
file = /etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${extract{1}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/accounts}}}}.msg
from = "${extract{1}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/accounts}}}}@${lookup{$domain}dsearch{/etc/exim4/domains/}}"
headers = Content-Type: text/plain; charset=utf-8;\nContent-Transfer-Encoding: 8bit
subject = "${if def:h_Subject: {Autoreply: \"${rfc2047:$h_Subject:}\"} {Autoreply Message}}"
to = "${sender_address}"
devnull:
driver = appendfile
file = /dev/null
######################################################################
# RETRY CONFIGURATION #
######################################################################
begin retry
# Address or Domain Error Retries
# ----------------- ----- -------
* * F,2h,15m; G,16h,1h,1.5; F,4d,6h
######################################################################
# REWRITE CONFIGURATION #
######################################################################
begin rewrite
######################################################################

View File

@@ -0,0 +1,512 @@
######################################################################
# #
# Exim configuration file for Hestia Control Panel #
# #
######################################################################
#SPAMASSASSIN = yes
#SPAM_SCORE = 50
#SPAM_REJECT_SCORE = 100
#CLAMD = yes
smtp_banner = $smtp_active_hostname
smtp_active_hostname = ${lookup dnsdb{>: defer_never,ptr=$interface_address}{${listextract{1}{$value}}}{$primary_hostname}}
add_environment = <; PATH=/bin:/usr/bin
keep_environment =
disable_ipv6 = true
SRS_SECRET = ${readfile{/etc/exim4/srs.conf}}
smtputf8_advertise_hosts =
domainlist local_domains = dsearch;/etc/exim4/domains/
domainlist relay_to_domains = dsearch;/etc/exim4/domains/
hostlist relay_from_hosts = 127.0.0.1
hostlist whitelist = net-iplsearch;/etc/exim4/white-blocks.conf
hostlist spammers = net-iplsearch;/etc/exim4/spam-blocks.conf
no_local_from_check
untrusted_set_sender = *
acl_smtp_connect = acl_check_spammers
acl_smtp_mail = acl_check_mail
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
acl_smtp_mime = acl_check_mime
.ifdef SPAMASSASSIN
spamd_address = 127.0.0.1 783
.endif
.ifdef CLAMD
av_scanner = clamd: /run/clamav/clamd.ctl
.endif
log_selector = +tls_sni
tls_advertise_hosts = *
# We test that $tls_in_sni is a valid domain, by an arbitrary email address foo@domain.tld .
# Then, we extract the domain with a function that would fail if the email address is invalid.
# If the certificate exists, we will use it, otherwise the default certificate in /etc/ssl will be used.
tls_certificate = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.crt} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.crt}\
{/usr/local/hestia/ssl/certificate.crt}\
}
tls_privatekey = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.key} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.key}\
{/usr/local/hestia/ssl/certificate.key}\
}
daemon_smtp_ports = 25 : 465 : 587
tls_on_connect_ports = 465
tls_require_ciphers = PERFORMANCE:-RSA:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3:%SERVER_PRECEDENCE
never_users = root
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 0s
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim4/domains/${lookup{${lc:${domain:$h_from:}}}dsearch{/etc/exim4/domains/}}/dkim.pem
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
OUTGOING_IP = /etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/ip
SMTP_RELAY_FILE = ${if exists{/etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/smtp_relay.conf}{/etc/exim4/domains/${lookup{$sender_address_domain}dsearch{/etc/exim4/domains}}/smtp_relay.conf}{/etc/exim4/smtp_relay.conf}}
SMTP_RELAY_HOST = ${lookup{host}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PORT = ${lookup{port}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_USER = ${lookup{user}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PASS = ${lookup{pass}lsearch{SMTP_RELAY_FILE}}
# Custom Filter
system_filter = /etc/exim4/system.filter
system_filter_user = Debian-exim
######################################################################
# ACL CONFIGURATION #
# Specifies access control lists for incoming SMTP mail #
######################################################################
acl_not_smtp = acl_not_smtp
begin acl
# Limit per user for PHP scripts
acl_not_smtp:
deny message = Website of user $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
ratelimit = 200 / 1h / $authenticated_id
warn ratelimit = 100 / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / account / $authenticated_id / $sender_rate / $sender_rate_period
accept
acl_check_spammers:
accept hosts = +whitelist
drop message = Your host in blacklist on this server.
log_message = Host in blacklist
hosts = +spammers
accept
acl_check_mail:
deny condition = ${if eq{$sender_helo_name}{}}
message = HELO required before MAIL
drop !authenticated = *
message = Helo name contains an IP address (HELO was $sender_helo_name) and not is valid
condition = ${if match{$sender_helo_name}{\N((\d{1,3}[.-]\d{1,3}[.-]\d{1,3}[.-]\d{1,3})|([0-9a-f]{8})|([0-9A-F]{8}))\N}{yes}{no}}
condition = ${if match {${lookup dnsdb{>: defer_never,ptr=$sender_host_address}}\}{$sender_helo_name}{no}{yes}}
delay = 45s
drop !authenticated = *
condition = ${if isip{$sender_helo_name}}
message = Access denied - Invalid HELO name (See RFC2821 4.1.3)
drop !authenticated = *
condition = ${if eq{[$interface_address]}{$sender_helo_name}}
message = $interface_address is _my_ address
accept
acl_check_rcpt:
accept hosts = :
# Limit per email account for SMTP auhenticated users
deny message = Email account $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
set acl_c_msg_limit = ${if exists{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{${lookup {$authenticated_id} lsearch{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{$value}{${readfile{/etc/exim4/limit.conf}}}}}{${readfile{/etc/exim4/limit.conf}}} }
ratelimit = $acl_c_msg_limit / 1h / strict/ $authenticated_id
warn ratelimit = ${eval:$acl_c_msg_limit / 2} / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / email / $authenticated_id / $sender_rate / $sender_rate_period
deny message = Restricted characters in address
domains = +local_domains
local_parts = ^[.] : ^.*[@%!/|]
deny message = Restricted characters in address
domains = !+local_domains
local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
require verify = sender
accept hosts = +relay_from_hosts
control = submission
accept authenticated = *
control = submission/domain=
deny message = Rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
hosts = !+whitelist
dnslists = ${readfile {/etc/exim4/dnsbl.conf}{:}}
require message = relay not permitted
domains = +local_domains : +relay_to_domains
deny message = smtp auth required
sender_domains = +local_domains
!authenticated = *
require verify = recipient
.ifdef CLAMD
warn set acl_m0 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antivirus}{yes}{no}}
set acl_m0 = yes
.endif
.ifdef SPAMASSASSIN
warn set acl_m1 = no
set acl_m3 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antispam}{yes}{no}}
set acl_m1 = yes
warn condition = ${if exists {/etc/exim4/domains/$domain/reject_spam}{yes}{no}}
set acl_m3 = yes
.endif
accept
acl_check_data:
.ifdef CLAMD
deny message = Message contains a virus ($malware_name) and has been rejected
malware = */defer_ok
condition = ${if eq{$acl_m0}{yes}{yes}{no}}
.endif
.ifdef SPAMASSASSIN
warn !authenticated = *
hosts = !+relay_from_hosts
condition = ${if < {$message_size}{1024K}}
condition = ${if eq{$acl_m1}{yes}{yes}{no}}
spam = debian-spamd:true/defer_ok
add_header = X-Spam-Score: $spam_score_int
add_header = X-Spam-Bar: $spam_bar
add_header = X-Spam-Report: $spam_report
set acl_m2 = $spam_score_int
warn condition = ${if !eq{$acl_m2}{} {yes}{no}}
condition = ${if >{$acl_m2}{SPAM_SCORE} {yes}{no}}
add_header = X-Spam-Status: Yes
message = SpamAssassin detected spam (from $sender_address to $recipients).
# Deny spam at high score if spam score > SPAM_REJECT_SCORE and delete_spam is enabled
deny message = This message scored $spam_score spam points
spam = debian-spamd:true
condition = ${if eq{$acl_m3}{yes}{yes}{no}}
condition = ${if >{$spam_score_int}{SPAM_REJECT_SCORE}{1}{0}}
.endif
accept
acl_check_mime:
deny message = Blacklisted file extension detected
condition = ${if match {${lc:$mime_filename}}{\N(\.ace|\.ade|\.adp|\.app|\.arj|\.asp|\.aspx|\.asx|\.bas|\.bat|\.cab|\.cer|\.chm|\.cmd|\.cnt|\.com|\.cpl|\.crt|\.csh|\.der|\.diagcab|\.dll|\.efi|\.exe|\.fla|\.fon|\.fxp|\.gadget|\.grp|\.hlp|\.hpj|\.hta|\.htc|\.img|\.inf|\.ins|\.iso|\.isp|\.its|\.jar|\.jnlp|\.js|\.jse|\.ksh|\.lib|\.lnk|\.mad|\.maf|\.mag|\.mam|\.maq|\.mar|\.mas|\.mat|\.mau|\.mav|\.maw|\.mcf|\.mda|\.mdb|\.mde|\.mdt|\.mdw|\.mdz|\.msc|\.msh|\.msh1|\.msh1xml|\.msh2|\.msh2xml|\.mshxml|\.msi|\.msp|\.mst|\.msu|\.ops|\.osd|\.pcd|\.pif|\.pl|\.plg|\.prf|\.prg|\.printerexport|\.ps1|\.ps1xml|\.ps2|\.ps2xml|\.psc1|\.psc2|\.psd1|\.psdm1|\.pst|\.py|\.pyc|\.pyo|\.pyw|\.pyz|\.pyzw|\.reg|\.scf|\.scr|\.sct|\.sfx|\.shb|\.shs|\.swf|\.sys|\.theme|\.tmp|\.ttf|\.url|\.vb|\.vba|\.vbe|\.vbp|\.vbs|\.vhd|\.vhdx|\.vsmacros|\.vsw|\.vxd|\.webpnp|\.website|\.wim|\.ws|\.wsc|\.wsf|\.wsh|\.xbap|\.xll|\.xnk)$\N}{1}{0}}
accept
######################################################################
# AUTHENTICATION CONFIGURATION #
######################################################################
begin authenticators
smtp_relay_login:
driver = plaintext
public_name = LOGIN
hide client_send = : SMTP_RELAY_USER : SMTP_RELAY_PASS
dovecot_plain:
driver = dovecot
public_name = PLAIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
dovecot_login:
driver = dovecot
public_name = LOGIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
######################################################################
# ROUTERS CONFIGURATION #
# Specifies how addresses are handled #
######################################################################
begin routers
send_via_unauthenticated_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
condition = ${if eq{SMTP_RELAY_USER}{}}
transport = remote_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
send_via_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
transport = smtp_relay_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
dnslookup:
driver = dnslookup
# if outbound, and forwarding has been done, use an alternate transport
domains = ! +local_domains
transport = ${if eq {$local_part@$domain} \
{$original_local_part@$original_domain} \
{remote_smtp} {remote_forwarded_smtp}}
no_more
userforward:
driver = redirect
check_local_user
file = $home/.forward
require_files = ${local_part}:+${home}/.forward
domains = +local_domains
allow_filter
no_verify
no_expn
check_ancestor
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
procmail:
driver = accept
check_local_user
require_files = ${local_part}:+${home}/.procmailrc:/usr/bin/procmail
transport = procmail
no_verify
autoreplay:
driver = accept
require_files = /etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${local_part}.msg
condition = ${if exists{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${local_part}.msg}{yes}{no}}
retry_use_local_part
transport = userautoreply
unseen
inbound_srs:
driver = redirect
senders = :
domains = +local_domains
# detect inbound bounces which are SRS'd, and decode them
condition = ${if inbound_srs {$local_part} {SRS_SECRET}}
data = $srs_recipient
inbound_srs_failure:
driver = redirect
senders = :
domains = +local_domains
# detect inbound bounces which look SRS'd but are invalid
condition = ${if inbound_srs {$local_part} {}}
allow_fail
data = :fail: Invalid SRS recipient address
aliases:
driver = redirect
headers_add = X-redirected: yes
data = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}}}}
require_files = /etc/exim4/domains/$domain/aliases
redirect_router = dnslookup
pipe_transport = address_pipe
unseen
localuser_fwd_only:
driver = accept
transport = devnull
condition = ${if exists{/etc/exim4/domains/$domain/fwd_only}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/fwd_only}{true}{false}}}}
localuser_spam:
driver = accept
transport = local_spam_delivery
condition = ${if eq {${if match{$h_X-Spam-Status:}{\N^Yes\N}{yes}{no}}} {${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}{yes}{no_such_user}}}}
localuser:
driver = accept
transport = local_delivery
condition = ${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}{true}{false}}
catchall:
driver = redirect
headers_add = X-redirected: yes
require_files = /etc/exim4/domains/$domain/aliases
data = ${extract{1}{:}{${lookup{*@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}}}}
file_transport = local_delivery
redirect_router = dnslookup
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}{false}{true}}
terminate_alias:
driver = accept
transport = devnull
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}{true}{false}}
######################################################################
# TRANSPORTS CONFIGURATION #
######################################################################
begin transports
smtp_relay_smtp:
driver = smtp
hosts_require_auth = $host_address
hosts_require_tls = $host_address
remote_smtp:
driver = smtp
helo_data = ${lookup dnsdb{>: defer_never,ptr=$sending_ip_address}{${listextract{1}{$value}}}{$primary_hostname}}
dkim_domain = DKIM_DOMAIN
dkim_selector = mail
dkim_private_key = DKIM_PRIVATE_KEY
dkim_canon = relaxed
dkim_strict = 0
hosts_try_fastopen = !*.l.google.com
interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}
remote_forwarded_smtp:
driver = smtp
helo_data = ${lookup dnsdb{>: defer_never,ptr=$sending_ip_address}{${listextract{1}{$value}}}{$primary_hostname}}
dkim_domain = DKIM_DOMAIN
dkim_selector = mail
dkim_private_key = DKIM_PRIVATE_KEY
dkim_canon = relaxed
dkim_strict = 0
hosts_try_fastopen = !*.l.google.com
interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}
# modify the envelope from, for mails that we forward
max_rcpt = 1
return_path = ${srs_encode {SRS_SECRET} {$return_path} {$original_domain}}
procmail:
driver = pipe
command = "/usr/bin/procmail -d $local_part"
return_path_add
delivery_date_add
envelope_to_add
user = $local_part
initgroups
return_output
local_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M
quota_warn_threshold = 75%
local_spam_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}/.Spam"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}M
quota_directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}/${lookup{$local_part}dsearch{${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/passwd}}}}/mail/${lookup{$domain}dsearch{/etc/exim4/domains/}}}}"
quota_warn_threshold = 75%
address_pipe:
driver = pipe
return_output
address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add
address_reply:
driver = autoreply
userautoreply:
driver = autoreply
file = /etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/autoreply.${extract{1}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/accounts}}}}.msg
from = "${extract{1}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/accounts}}}}@${lookup{$domain}dsearch{/etc/exim4/domains/}}"
headers = Content-Type: text/plain; charset=utf-8;\nContent-Transfer-Encoding: 8bit
subject = "${if def:h_Subject: {Autoreply: \"${rfc2047:$h_Subject:}\"} {Autoreply Message}}"
to = "${sender_address}"
devnull:
driver = appendfile
file = /dev/null
######################################################################
# RETRY CONFIGURATION #
######################################################################
begin retry
# Address or Domain Error Retries
# ----------------- ----- -------
* * F,2h,15m; G,16h,1h,1.5; F,4d,6h
######################################################################
# REWRITE CONFIGURATION #
######################################################################
begin rewrite
######################################################################

View File

@@ -0,0 +1,478 @@
######################################################################
# #
# Exim configuration file for Hestia Control Panel #
# #
######################################################################
#SPAMASSASSIN = yes
#SPAM_SCORE = 50
#SPAM_REJECT_SCORE = 100
#CLAMD = yes
smtp_banner = $smtp_active_hostname
smtp_active_hostname = ${lookup dnsdb{>: defer_never,ptr=$interface_address}{${listextract{1}{$value}}}{$primary_hostname}}
add_environment = <; PATH=/bin:/usr/bin
keep_environment =
disable_ipv6 = true
smtputf8_advertise_hosts =
domainlist local_domains = dsearch;/etc/exim4/domains/
domainlist relay_to_domains = dsearch;/etc/exim4/domains/
hostlist relay_from_hosts = 127.0.0.1
hostlist whitelist = net-iplsearch;/etc/exim4/white-blocks.conf
hostlist spammers = net-iplsearch;/etc/exim4/spam-blocks.conf
no_local_from_check
untrusted_set_sender = *
acl_smtp_connect = acl_check_spammers
acl_smtp_mail = acl_check_mail
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data
acl_smtp_mime = acl_check_mime
.ifdef SPAMASSASSIN
spamd_address = 127.0.0.1 783
.endif
.ifdef CLAMD
av_scanner = clamd: /run/clamav/clamd.ctl
.endif
log_selector = +tls_sni
tls_advertise_hosts = *
# We test that $tls_in_sni is a valid domain, by an arbitrary email address foo@domain.tld .
# Then, we extract the domain with a function that would fail if the email address is invalid.
# If the certificate exists, we will use it, otherwise the default certificate in /etc/ssl will be used.
tls_certificate = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.crt} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.crt}\
{/usr/local/hestia/ssl/certificate.crt}\
}
tls_privatekey = \
${if and {\
{ eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
{ exists{/usr/local/hestia/ssl/mail/$tls_in_sni.key} }\
}\
{/usr/local/hestia/ssl/mail/$tls_in_sni.key}\
{/usr/local/hestia/ssl/certificate.key}\
}
daemon_smtp_ports = 25 : 465 : 587
tls_on_connect_ports = 465
tls_require_ciphers = PERFORMANCE:-RSA:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3:%SERVER_PRECEDENCE
never_users = root
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 0s
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/exim4/domains/${lc:${domain:$h_from:}}/dkim.pem
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
OUTGOING_IP = /etc/exim4/domains/$sender_address_domain/ip
SMTP_RELAY_FILE = ${if exists{/etc/exim4/domains/${sender_address_domain}/smtp_relay.conf}{/etc/exim4/domains/$sender_address_domain/smtp_relay.conf}{/etc/exim4/smtp_relay.conf}}
SMTP_RELAY_HOST = ${lookup{host}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PORT = ${lookup{port}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_USER = ${lookup{user}lsearch{SMTP_RELAY_FILE}}
SMTP_RELAY_PASS = ${lookup{pass}lsearch{SMTP_RELAY_FILE}}
# Custom Filter
system_filter = /etc/exim4/system.filter
system_filter_user = Debian-exim
######################################################################
# ACL CONFIGURATION #
# Specifies access control lists for incoming SMTP mail #
######################################################################
acl_not_smtp = acl_not_smtp
begin acl
# Limit per user for PHP scripts
acl_not_smtp:
deny message = Website of user $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
ratelimit = 200 / 1h / $authenticated_id
warn ratelimit = 100 / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / account / $authenticated_id / $sender_rate / $sender_rate_period
accept
acl_check_spammers:
accept hosts = +whitelist
drop message = Your host in blacklist on this server.
log_message = Host in blacklist
hosts = +spammers
accept
acl_check_mail:
deny condition = ${if eq{$sender_helo_name}{}}
message = HELO required before MAIL
drop !authenticated = *
message = Helo name contains an IP address (HELO was $sender_helo_name) and not is valid
condition = ${if match{$sender_helo_name}{\N((\d{1,3}[.-]\d{1,3}[.-]\d{1,3}[.-]\d{1,3})|([0-9a-f]{8})|([0-9A-F]{8}))\N}{yes}{no}}
condition = ${if match {${lookup dnsdb{>: defer_never,ptr=$sender_host_address}}\}{$sender_helo_name}{no}{yes}}
delay = 45s
drop !authenticated = *
condition = ${if isip{$sender_helo_name}}
message = Access denied - Invalid HELO name (See RFC2821 4.1.3)
drop !authenticated = *
condition = ${if eq{[$interface_address]}{$sender_helo_name}}
message = $interface_address is _my_ address
accept
acl_check_rcpt:
accept hosts = :
# Limit per email account for SMTP auhenticated users
deny message = Email account $authenticated_id is sending too many emails - rate overlimit = $sender_rate / $sender_rate_period
set acl_c_msg_limit = ${if exists{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{${lookup {$authenticated_id} lsearch{/etc/exim4/domains/${lookup{${domain:$authenticated_id}}dsearch{/etc/exim4/domains/}}/limits}{$value}{${readfile{/etc/exim4/limit.conf}}}}}{${readfile{/etc/exim4/limit.conf}}} }
ratelimit = $acl_c_msg_limit / 1h / strict/ $authenticated_id
warn ratelimit = ${eval:$acl_c_msg_limit / 2} / 1h / strict / $authenticated_id
log_message = Sender rate [limitlog]: log / email / $authenticated_id / $sender_rate / $sender_rate_period
deny message = Restricted characters in address
domains = +local_domains
local_parts = ^[.] : ^.*[@%!/|]
deny message = Restricted characters in address
domains = !+local_domains
local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
require verify = sender
accept hosts = +relay_from_hosts
control = submission
accept authenticated = *
control = submission/domain=
deny message = Rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
hosts = !+whitelist
dnslists = ${readfile {/etc/exim4/dnsbl.conf}{:}}
require message = relay not permitted
domains = +local_domains : +relay_to_domains
deny message = smtp auth required
sender_domains = +local_domains
!authenticated = *
require verify = recipient
.ifdef CLAMD
warn set acl_m0 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antivirus}{yes}{no}}
set acl_m0 = yes
.endif
.ifdef SPAMASSASSIN
warn set acl_m1 = no
set acl_m3 = no
warn condition = ${if exists {/etc/exim4/domains/$domain/antispam}{yes}{no}}
set acl_m1 = yes
warn condition = ${if exists {/etc/exim4/domains/$domain/reject_spam}{yes}{no}}
set acl_m3 = yes
.endif
accept
acl_check_data:
.ifdef CLAMD
deny message = Message contains a virus ($malware_name) and has been rejected
malware = */defer_ok
condition = ${if eq{$acl_m0}{yes}{yes}{no}}
.endif
.ifdef SPAMASSASSIN
warn !authenticated = *
hosts = !+relay_from_hosts
condition = ${if < {$message_size}{1024K}}
condition = ${if eq{$acl_m1}{yes}{yes}{no}}
spam = debian-spamd:true/defer_ok
add_header = X-Spam-Score: $spam_score_int
add_header = X-Spam-Bar: $spam_bar
add_header = X-Spam-Report: $spam_report
set acl_m2 = $spam_score_int
warn condition = ${if !eq{$acl_m2}{} {yes}{no}}
condition = ${if >{$acl_m2}{SPAM_SCORE} {yes}{no}}
add_header = X-Spam-Status: Yes
message = SpamAssassin detected spam (from $sender_address to $recipients).
# Deny spam at high score if spam score > SPAM_REJECT_SCORE and delete_spam is enabled
deny message = This message scored $spam_score spam points
spam = debian-spamd:true
condition = ${if eq{$acl_m3}{yes}{yes}{no}}
condition = ${if >{$spam_score_int}{SPAM_REJECT_SCORE}{1}{0}}
.endif
accept
acl_check_mime:
deny message = Blacklisted file extension detected
condition = ${if match {${lc:$mime_filename}}{\N(\.ace|\.ade|\.adp|\.app|\.arj|\.asp|\.aspx|\.asx|\.bas|\.bat|\.cab|\.cer|\.chm|\.cmd|\.cnt|\.com|\.cpl|\.crt|\.csh|\.der|\.diagcab|\.dll|\.efi|\.exe|\.fla|\.fon|\.fxp|\.gadget|\.grp|\.hlp|\.hpj|\.hta|\.htc|\.img|\.inf|\.ins|\.iso|\.isp|\.its|\.jar|\.jnlp|\.js|\.jse|\.ksh|\.lib|\.lnk|\.mad|\.maf|\.mag|\.mam|\.maq|\.mar|\.mas|\.mat|\.mau|\.mav|\.maw|\.mcf|\.mda|\.mdb|\.mde|\.mdt|\.mdw|\.mdz|\.msc|\.msh|\.msh1|\.msh1xml|\.msh2|\.msh2xml|\.mshxml|\.msi|\.msp|\.mst|\.msu|\.ops|\.osd|\.pcd|\.pif|\.pl|\.plg|\.prf|\.prg|\.printerexport|\.ps1|\.ps1xml|\.ps2|\.ps2xml|\.psc1|\.psc2|\.psd1|\.psdm1|\.pst|\.py|\.pyc|\.pyo|\.pyw|\.pyz|\.pyzw|\.reg|\.scf|\.scr|\.sct|\.sfx|\.shb|\.shs|\.swf|\.sys|\.theme|\.tmp|\.ttf|\.url|\.vb|\.vba|\.vbe|\.vbp|\.vbs|\.vhd|\.vhdx|\.vsmacros|\.vsw|\.vxd|\.webpnp|\.website|\.wim|\.ws|\.wsc|\.wsf|\.wsh|\.xbap|\.xll|\.xnk)$\N}{1}{0}}
accept
######################################################################
# AUTHENTICATION CONFIGURATION #
######################################################################
begin authenticators
smtp_relay_login:
driver = plaintext
public_name = LOGIN
hide client_send = : SMTP_RELAY_USER : SMTP_RELAY_PASS
dovecot_plain:
driver = dovecot
public_name = PLAIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
dovecot_login:
driver = dovecot
public_name = LOGIN
server_socket = /run/dovecot/auth-client
server_set_id = $auth1
######################################################################
# ROUTERS CONFIGURATION #
# Specifies how addresses are handled #
######################################################################
begin routers
send_via_unauthenticated_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
condition = ${if eq{SMTP_RELAY_USER}{}}
transport = remote_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
send_via_smtp_relay:
driver = manualroute
address_data = SMTP_RELAY_HOST:SMTP_RELAY_PORT
domains = !+local_domains
require_files = SMTP_RELAY_FILE
transport = smtp_relay_smtp
route_list = * ${extract{1}{:}{$address_data}}::${extract{2}{:}{$address_data}}
no_more
no_verify
dnslookup:
driver = dnslookup
domains = !+local_domains
transport = remote_smtp
no_more
userforward:
driver = redirect
check_local_user
file = $home/.forward
require_files = ${local_part}:+${home}/.forward
domains = +local_domains
allow_filter
no_verify
no_expn
check_ancestor
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
procmail:
driver = accept
check_local_user
require_files = ${local_part}:+${home}/.procmailrc:/usr/bin/procmail
transport = procmail
no_verify
autoreplay:
driver = accept
require_files = /etc/exim4/domains/$domain/autoreply.${local_part}.msg
condition = ${if exists{/etc/exim4/domains/$domain/autoreply.${local_part}.msg}{yes}{no}}
retry_use_local_part
transport = userautoreply
unseen
aliases:
driver = redirect
headers_add = X-redirected: yes
data = ${extract{1}{:}{${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/$domain/aliases}}}}
require_files = /etc/exim4/domains/$domain/aliases
redirect_router = dnslookup
pipe_transport = address_pipe
unseen
localuser_fwd_only:
driver = accept
transport = devnull
condition = ${if exists{/etc/exim4/domains/$domain/fwd_only}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/fwd_only}{true}{false}}}}
localuser_spam:
driver = accept
transport = local_spam_delivery
condition = ${if eq {${if match{$h_X-Spam-Status:}{\N^Yes\N}{yes}{no}}} {${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}{yes}{no_such_user}}}}
localuser:
driver = accept
transport = local_delivery
condition = ${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}{true}{false}}
catchall:
driver = redirect
headers_add = X-redirected: yes
require_files = /etc/exim4/domains/$domain/aliases
data = ${extract{1}{:}{${lookup{*@$domain}lsearch{/etc/exim4/domains/$domain/aliases}}}}
file_transport = local_delivery
redirect_router = dnslookup
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/${lookup{$domain}dsearch{/etc/exim4/domains/}}/aliases}{false}{true}}
terminate_alias:
driver = accept
transport = devnull
condition = ${lookup{$local_part@$domain}lsearch{/etc/exim4/domains/$domain/aliases}{true}{false}}
######################################################################
# TRANSPORTS CONFIGURATION #
######################################################################
begin transports
smtp_relay_smtp:
driver = smtp
hosts_require_auth = $host_address
hosts_require_tls = $host_address
remote_smtp:
driver = smtp
helo_data = ${lookup dnsdb{>: defer_never,ptr=$sending_ip_address}{${listextract{1}{$value}}}{$primary_hostname}}
dkim_domain = DKIM_DOMAIN
dkim_selector = mail
dkim_private_key = DKIM_PRIVATE_KEY
dkim_canon = relaxed
dkim_strict = 0
hosts_try_fastopen = !*.l.google.com
interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}
procmail:
driver = pipe
command = "/usr/bin/procmail -d $local_part"
return_path_add
delivery_date_add
envelope_to_add
user = $local_part
initgroups
return_output
local_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}M
quota_warn_threshold = 75%
local_spam_delivery:
driver = appendfile
maildir_format
maildir_use_size_file
user = ${extract{2}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}
group = mail
create_directory
directory_mode = 770
mode = 660
use_lockfile = no
delivery_date_add
envelope_to_add
return_path_add
directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part/.Spam"
quota = ${extract{6}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}M
quota_directory = "${extract{5}{:}{${lookup{$local_part}lsearch{/etc/exim4/domains/$domain/passwd}}}}/mail/$domain/$local_part"
quota_warn_threshold = 75%
address_pipe:
driver = pipe
return_output
address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add
address_reply:
driver = autoreply
userautoreply:
driver = autoreply
file = /etc/exim4/domains/$domain/autoreply.${local_part}.msg
from = "${local_part}@${domain}"
headers = Content-Type: text/plain; charset=utf-8;\nContent-Transfer-Encoding: 8bit
subject = "${if def:h_Subject: {Autoreply: \"${rfc2047:$h_Subject:}\"} {Autoreply Message}}"
to = "${sender_address}"
devnull:
driver = appendfile
file = /dev/null
######################################################################
# RETRY CONFIGURATION #
######################################################################
begin retry
# Address or Domain Error Retries
# ----------------- ----- -------
* * F,2h,15m; G,16h,1h,1.5; F,4d,6h
######################################################################
# REWRITE CONFIGURATION #
######################################################################
begin rewrite
######################################################################

View File

@@ -0,0 +1 @@
200

View File

View File

@@ -0,0 +1 @@
TOBEREPLACED

View File

@@ -0,0 +1,16 @@
if $h_X-Spam-Status: contains "Yes"
then
headers add "Old-Subject: $h_subject"
headers remove "Subject"
headers add "Subject: *** SPAM *** $h_old-subject"
headers remove "Old-Subject"
endif
# X-Anti-Virus: infected
if $h_X-Anti-Virus: contains "infected"
then
headers add "Old-Subject: $h_subject"
headers remove "Subject"
headers add "Subject: *** VIRUS *** $h_old-subject"
headers remove "Old-Subject"
endif

View File

@@ -0,0 +1,9 @@
# Fail2Ban configuration file for hestia
[Definition]
actionstart = /usr/local/hestia/bin/v-add-firewall-chain <name>
actionstop = /usr/local/hestia/bin/v-delete-firewall-chain <name>
actioncheck = iptables -n -L INPUT | grep -q 'fail2ban-<name>[ \t]'
actionban = /usr/local/hestia/bin/v-add-firewall-ban <ip> <name>
actionunban = /usr/local/hestia/bin/v-delete-firewall-ban <ip> <name>

View File

@@ -0,0 +1,10 @@
# Fail2Ban filter for unsuccessful hestia authentication attempts
#
[INCLUDES]
before = common.conf
[Definition]
failregex = .* <HOST> failed to login
ignoreregex =

View File

@@ -0,0 +1,66 @@
[ssh-iptables]
enabled = true
filter = sshd
action = hestia[name=SSH]
logpath = /var/log/auth.log
maxretry = 5
[vsftpd-iptables]
enabled = false
filter = vsftpd
action = hestia[name=FTP]
logpath = /var/log/vsftpd.log
maxretry = 5
[exim-iptables]
enabled = true
filter = exim
action = hestia[name=MAIL]
logpath = /var/log/exim4/mainlog
[dovecot-iptables]
enabled = true
filter = dovecot
action = hestia[name=MAIL]
logpath = /var/log/dovecot.log
[mysqld-iptables]
enabled = false
filter = mysqld-auth
action = hestia[name=DB]
logpath = /var/log/mysql/error.log
maxretry = 5
[hestia-iptables]
enabled = true
filter = hestia
action = hestia[name=HESTIA]
logpath = /var/log/hestia/auth.log
maxretry = 5
[roundcube-auth]
enabled = false
filter = roundcube-auth
action = hestia[name=WEB]
logpath = /var/log/roundcube/errors.log
maxretry = 5
[phpmyadmin-auth]
enabled = true
filter = phpmyadmin-syslog
action = hestia[name=WEB]
logpath = /var/log/auth.log
maxretry = 5
[recidive]
enabled = true
filter = recidive
action = hestia[name=RECIDIVE]
logpath = /var/log/fail2ban.log
maxretry = 5
findtime = 86400
bantime = 864000
#Uncomment and add your IPs and or domains to the Whitelist
#[DEFAULT]
#ignoreip = 111.111.111.111 222.222.222.222 subdomain.example.tld example.tld 333.333.333.333

View File

@@ -0,0 +1,48 @@
<?php
namespace Filegator\Services\Archiver\Adapters;
use Filegator\Container\Container;
use Filegator\Services\Archiver\ArchiverInterface;
use Filegator\Services\Service;
use Filegator\Services\Storage\Filesystem as Storage;
use Filegator\Services\Tmpfs\TmpfsInterface;
use function Hestiacp\quoteshellarg\quoteshellarg;
class HestiaZipArchiver extends ZipArchiver implements Service, ArchiverInterface {
protected $container;
public function __construct(TmpfsInterface $tmpfs, Container $container) {
$this->tmpfs = $tmpfs;
$this->container = $container;
}
public function uncompress(string $source, string $destination, Storage $storage) {
$auth = $this->container->get("Filegator\Services\Auth\AuthInterface");
$v_user = basename($auth->user()->getUsername());
if (!strlen($v_user)) {
return;
}
if (strpos($source, "/home") === false) {
$source = "/home/$v_user/" . $source;
}
if (strpos($destination, "/home") === false) {
$destination = "/home/$v_user/" . $destination;
}
exec(
"sudo /usr/local/hestia/bin/v-extract-fs-archive " .
quoteshellarg($v_user) .
" " .
quoteshellarg($source) .
" " .
quoteshellarg($destination),
$output,
$return_var,
);
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of the FileGator package.
*
* (c) Milos Stojanovic <alcalbg@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
*/
namespace Filegator\Services\Auth\Adapters;
use Filegator\Services\Auth\AuthInterface;
use Filegator\Services\Auth\User;
use Filegator\Services\Auth\UsersCollection;
use Filegator\Services\Service;
use function Hestiacp\quoteshellarg\quoteshellarg;
/**
* @codeCoverageIgnore
*/
class HestiaAuth implements Service, AuthInterface {
protected $permissions = [];
protected $private_repos = false;
protected $hestia_user = "";
public function init(array $config = []) {
if (isset($_SESSION["user"])) {
$v_user = $_SESSION["user"];
}
if (!empty($_SESSION["look"])) {
if (isset($_SESSION["look"]) && $_SESSION["userContext"] === "admin") {
$v_user = $_SESSION["look"];
}
if (
$_SESSION["look"] == "admin" &&
$_SESSION["POLICY_SYSTEM_PROTECTED_ADMIN"] == "yes"
) {
// Go away do not login
header("Location: /");
exit();
}
}
$this->hestia_user = $v_user;
$this->permissions = isset($config["permissions"]) ? (array) $config["permissions"] : [];
$this->private_repos = isset($config["private_repos"])
? (bool) $config["private_repos"]
: false;
}
public function user(): ?User {
$cmd = "/usr/bin/sudo /usr/local/hestia/bin/v-list-user";
exec($cmd . " " . quoteshellarg($this->hestia_user) . " json", $output, $return_var);
if ($return_var == 0) {
$data = json_decode(implode("", $output), true);
$hestia_user_info = $data[$this->hestia_user];
return $this->transformUser($hestia_user_info);
}
return $this->getGuest();
}
public function transformUser($hstuser): User {
$user = new User();
$user->setUsername($this->hestia_user);
$user->setName($this->hestia_user . " (" . $hstuser["NAME"] . ")");
$user->setRole("user");
$user->setPermissions($this->permissions);
$user->setHomedir("/");
return $user;
}
public function authenticate($username, $password): bool {
# Auth is handled by Hestia
return false;
}
public function forget() {
// Logout return to Hestia
return $this->getGuest();
}
public function store(User $user) {
return null; // not used
}
public function update($username, User $user, $password = ""): User {
// Password change is handled by Hestia
return $this->user();
}
public function add(User $user, $password): User {
return new User(); // not used
}
public function delete(User $user) {
return true; // not used
}
public function find($username): ?User {
return null; // not used
}
public function allUsers(): UsersCollection {
return new UsersCollection(); // not used
}
public function getGuest(): User {
$guest = new User();
$guest->setUsername("guest");
$guest->setName("Guest");
$guest->setRole("guest");
$guest->setHomedir("/");
$guest->setPermissions([]);
return $guest;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the FileGator package.
*
* (c) Milos Stojanovic <alcalbg@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
*/
namespace Filegator\Services\Session\Adapters;
use Filegator\Kernel\Request;
use Filegator\Services\Service;
use Filegator\Services\Session\Session;
use Filegator\Services\Session\SessionStorageInterface;
class SessionStorage implements Service, SessionStorageInterface {
protected $request;
protected $config;
public function __construct(Request $request) {
$this->request = $request;
}
public function init(array $config = []) {
// we don't have a previous session attached
if (!$this->getSession()) {
$handler = $config["handler"];
$session = new Session($handler());
//$session->setName('filegator');
$this->setSession($session);
}
}
public function save() {
$this->getSession()->save();
}
public function set(string $key, $data) {
return $this->getSession()->set($key, $data);
}
public function get(string $key, $default = null) {
return $this->getSession() ? $this->getSession()->get($key, $default) : $default;
}
public function invalidate() {
if (!$this->getSession()->isStarted()) {
$this->getSession()->start();
}
$this->getSession()->invalidate();
}
private function setSession(Session $session) {
return $this->request->setSession($session);
}
private function getSession(): ?Session {
return $this->request->getSession();
}
}

View File

@@ -0,0 +1,47 @@
{
"name": "filegator/filegator",
"description": "Filegator",
"license": "MIT",
"type": "project",
"config": {
"platform": {
"php": "7.2.5"
}
},
"require": {
"php": "^7.2",
"monolog/monolog": "^1.24",
"nikic/fast-route": "^1.3",
"symfony/security-csrf": "^4.4",
"symfony/http-foundation": "^4.4",
"dibi/dibi": "^4.1",
"php-di/php-di": "^6.0",
"rakit/validation": "^1.1",
"league/flysystem": "^1.1",
"league/flysystem-ziparchive": "^1.0",
"league/flysystem-sftp": "^1.0",
"hestiacp/phpquoteshellarg": "^1.0"
},
"authors": [
{
"name": "Milos Stojanovic",
"email": "alcalbg@gmail.com"
}
],
"autoload": {
"psr-4": {
"Filegator\\": "backend"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/backend/"
}
},
"require-dev": {
"phpunit/phpunit": "^8.0",
"symfony/var-dumper": "^4.4",
"league/flysystem-memory": "^1.0",
"phpstan/phpstan": "^0.11.8"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
<?php
use function Hestiacp\quoteshellarg\quoteshellarg;
$dist_config = require __DIR__ . "/configuration_sample.php";
$dist_config["public_path"] = "/fm/";
$dist_config["frontend_config"]["app_name"] = "File Manager - Hestia Control Panel";
$dist_config["frontend_config"]["logo"] = "../images/logo.svg";
$dist_config["frontend_config"]["editable"] = [
".txt",
".css",
".js",
".ts",
".html",
".php",
".py",
".yml",
".xml",
".md",
".log",
".csv",
".conf",
".config",
".ini",
".scss",
".sh",
".env",
".example",
".htaccess",
".twig",
".tpl",
".yaml",
];
$dist_config["frontend_config"]["guest_redirection"] = "/login/";
$dist_config["frontend_config"]["upload_max_size"] = 1024 * 1024 * 1024;
$dist_config["services"]["Filegator\Services\Storage\Filesystem"]["config"][
"adapter"
] = function () {
if (!empty($_SESSION["INACTIVE_SESSION_TIMEOUT"])) {
if ($_SESSION["INACTIVE_SESSION_TIMEOUT"] * 60 + $_SESSION["LAST_ACTIVITY"] < time()) {
$v_user = quoteshellarg($_SESSION["user"]);
$v_session_id = quoteshellarg($_SESSION["token"]);
exec(
"/usr/local/hestia/bin/v-log-user-logout " . $v_user . " " . $v_session_id,
$output,
$return_var,
);
unset($_SESSION);
session_unset();
session_destroy();
session_start();
echo '<meta http-equiv="refresh" content="0; url=/">';
exit();
} else {
$_SESSION["LAST_ACTIVITY"] = time();
}
} else {
echo '<meta http-equiv="refresh" content="0; url=/">';
}
if (isset($_SESSION["user"])) {
$v_user = $_SESSION["user"];
}
if (!empty($_SESSION["look"])) {
if (isset($_SESSION["look"]) && $_SESSION["userContext"] === "admin") {
$v_user = $_SESSION["look"];
}
if (
isset($_SESSION["look"]) &&
$_SESSION["look"] == "admin" &&
$_SESSION["POLICY_SYSTEM_PROTECTED_ADMIN"] == "yes"
) {
header("Location: /");
}
}
# Create filemanager sftp key if missing and trash it after 30 min
if (!file_exists("/home/" . basename($v_user) . "/.ssh/hst-filemanager-key")) {
exec(
"sudo /usr/local/hestia/bin/v-add-user-sftp-key " .
quoteshellarg(basename($v_user)) .
" 30",
$output,
$return_var,
);
// filemanager also requires .ssh chmod o+x ... hopefully we can improve it to g+x or u+x someday
// current minimum for filemanager: chmod 0701 .ssh
shell_exec("sudo chmod o+x " . quoteshellarg("/home/" . basename($v_user) . "/.ssh"));
}
if (!isset($_SESSION["SFTP_PORT"])) {
exec("sudo /usr/local/hestia/bin/v-list-sys-sshd-port json", $output, $result);
$port = json_decode(implode("", $output));
if (is_numeric($port[0]) && $port[0] > 0) {
$_SESSION["SFTP_PORT"] = $port[0];
} elseif (
preg_match('/^\s*Port\s+(\d+)$/im', file_get_contents("/etc/ssh/sshd_config"), $matches)
) {
$_SESSION["SFTP_PORT"] = $matches[1] ?? 22;
} else {
$_SESSION["SFTP_PORT"] = 22;
}
}
preg_match(
'/(Hestia SFTP Chroot\nMatch User)(.*)/i',
file_get_contents("/etc/ssh/sshd_config"),
$matches,
);
$user_list = explode(",", $matches[2]);
if (in_array($v_user, $user_list)) {
$root = "/";
} else {
$root = "/home/" . $v_user;
}
return new \League\Flysystem\Sftp\SftpAdapter([
"host" => "127.0.0.1",
"port" => intval($_SESSION["SFTP_PORT"]),
"username" => basename($v_user),
"privateKey" => "/home/" . basename($v_user) . "/.ssh/hst-filemanager-key",
"root" => $root,
"timeout" => 10,
"directoryPerm" => 0755,
]);
};
$dist_config["services"]["Filegator\Services\Archiver\ArchiverInterface"] = [
"handler" => "\Filegator\Services\Archiver\Adapters\HestiaZipArchiver",
"config" => [],
];
$dist_config["services"]["Filegator\Services\Auth\AuthInterface"] = [
"handler" => "\Filegator\Services\Auth\Adapters\HestiaAuth",
"config" => [
"permissions" => ["read", "write", "upload", "download", "batchdownload", "zip"],
"private_repos" => false,
],
];
$dist_config["services"]["Filegator\Services\View\ViewInterface"]["config"] = [
"add_to_head" => '
<style>
.logo {
width: 46px;
}
</style>
',
"add_to_body" => '
<script>
var checkVueLoaded = setInterval(function() {
if (document.getElementsByClassName("container").length) {
clearInterval(checkVueLoaded);
var navProfile = document.getElementsByClassName("navbar-item profile")[0]; navProfile.replaceWith(navProfile.cloneNode(true))
document.getElementsByClassName("navbar-item logout")[0].text="Exit to Control Panel \u00BB";
div = document.getElementsByClassName("container")[0];
callback = function(){
if (document.getElementsByClassName("navbar-item logout")[0]){
if ( document.getElementsByClassName("navbar-item logout")[0].text != "Exit to Control Panel \u00BB" ){
var navProfile = document.getElementsByClassName("navbar-item profile")[0]; navProfile.replaceWith(navProfile.cloneNode(true))
document.getElementsByClassName("navbar-item logout")[0].text="Exit to Control Panel \u00BB";
}
}
}
config = {
childList:true,
subtree:true
}
observer = new MutationObserver(callback);
observer.observe(div,config);
}
}, 200);
</script>',
];
return $dist_config;

View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Checking root permissions
if [ "x$(id -u)" != 'x0' ]; then
echo "Error: Script can be run executed only by root"
exit 10
fi
if [ -z "$HESTIA" ]; then
HESTIA="/usr/local/hestia"
fi
user='admin'
fm_error='no'
source $HESTIA/func/main.sh
source $HESTIA/install/upgrade/upgrade.conf
if [ -z "$HOMEDIR" ] || [ -z "$HESTIA_INSTALL_DIR" ]; then
echo "Error: Hestia environment vars not present"
exit 2
fi
FM_INSTALL_DIR="$HESTIA/web/fm"
FM_FILE="filegator_latest"
FM_URL="https://github.com/filegator/static/raw/master/builds/filegator_latest.zip"
COMPOSER_BIN="$HOMEDIR/$user/.composer/composer"
if [ ! -f "$COMPOSER_BIN" ]; then
$BIN/v-add-user-composer "$user"
if [ $? -ne 0 ]; then
$BIN/v-add-user-notification admin 'Composer installation failed!' '<p class="u-text-bold">The File Manager will not work without Composer.</p><p>Please try running the installer from a shell session:<br><code>bash $HESTIA/install/deb/filemanager/install-fm.sh</code></p><p>If this issue continues, please <a href="https://github.com/hestiacp/hestiacp/issues" target="_blank">open an issue on GitHub</a>.</p>'
fm_error='yes'
fi
fi
if [ "$fm_error" != "yes" ]; then
rm --recursive --force "$FM_INSTALL_DIR"
mkdir -p "$FM_INSTALL_DIR"
cd "$FM_INSTALL_DIR"
[ ! -f "${FM_INSTALL_DIR}/${FM_FILE}" ] && wget "$FM_URL" --quiet -O "${FM_INSTALL_DIR}/${FM_FILE}.zip"
unzip -qq "${FM_INSTALL_DIR}/${FM_FILE}.zip"
mv --force ${FM_INSTALL_DIR}/filegator/* "${FM_INSTALL_DIR}"
rm --recursive --force ${FM_INSTALL_DIR}/${FM_FILE}
[[ -f "${FM_INSTALL_DIR}/${FM_FILE}" ]] && rm "${FM_INSTALL_DIR}/${FM_FILE}"
cp --recursive --force ${HESTIA_INSTALL_DIR}/filemanager/filegator/* "${FM_INSTALL_DIR}"
chown $user: -R "${FM_INSTALL_DIR}"
# Check if php7.3 is available and run the installer
if [ -f "/usr/bin/php7.3" ]; then
COMPOSER_HOME="$HOMEDIR/$user/.config/composer" user_exec /usr/bin/php7.3 $COMPOSER_BIN --quiet --no-dev install
if [ $? -ne 0 ]; then
$BIN/v-add-user-notification admin 'File Manager installation failed!' '<p>Please try running the installer from a shell session:<br><code>bash $HESTIA/install/deb/filemanager/install-fm.sh</code></p><p>If this issue continues, please <a href="https://github.com/hestiacp/hestiacp/issues" target="_blank">open an issue on GitHub</a>.</p>'
fm_error="yes"
fi
else
$BIN/v-add-user-notification admin 'File Manager installation failed!' '<p class="u-text-bold">Unable to proceed with installation of File Manager.</p><p>Package <span class="u-text-bold">php7.3-cli</span> is missing from your system. Please check your PHP installation and environment settings.</p>'
fm_error="yes"
fi
if [ "$fm_error" != "yes" ]; then
chown root: -R "${FM_INSTALL_DIR}"
chown $user: "${FM_INSTALL_DIR}/private"
chown $user: "${FM_INSTALL_DIR}/private/logs"
chown $user: "${FM_INSTALL_DIR}/repository"
fi
fi

View File

@@ -0,0 +1,19 @@
/var/log/apache2/*.log /var/log/apache2/domains/*log {
rotate 4
weekly
missingok
notifempty
compress
delaycompress
create 640
sharedscripts
postrotate
/etc/init.d/apache2 reload > /dev/null || true
[ ! -f /run/nginx.pid ] || kill -USR1 `cat /run/nginx.pid`
endscript
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi; \
endscript
}

View File

@@ -0,0 +1,12 @@
/var/log/dovecot*.log {
rotate 4
weekly
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
doveadm log reopen
endscript
}

View File

@@ -0,0 +1,7 @@
/var/log/hestia/*.log {
rotate 12
monthly
missingok
notifempty
create 0600 root root
}

View File

@@ -0,0 +1,4 @@
#!/bin/sh
# Changes made by HestiaCP due to https://github.com/hestiacp/hestiacp/issues/3289
/usr/local/hestia/bin/v-update-sys-queue webstats

View File

@@ -0,0 +1,13 @@
/var/log/nginx/*log /var/log/nginx/domains/*log {
rotate 4
weekly
missingok
notifempty
compress
delaycompress
create 640
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}

View File

@@ -0,0 +1,7 @@
/var/log/roundcube/*.log {
rotate 12
monthly
missingok
notifempty
create 644 www-data www-data
}

View File

@@ -0,0 +1,50 @@
[client]
port=3306
socket=/run/mysqld/mysqld.sock
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld_safe]
socket=/run/mysqld/mysqld.sock
[mysqld]
user=mysql
pid-file=/run/mysqld/mysqld.pid
socket=/run/mysqld/mysqld.sock
port=3306
basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
lc-messages-dir=/usr/share/mysql
log_error=/var/log/mysql/error.log
collation-server = utf8mb4_unicode_520_ci
init-connect='SET NAMES utf8mb4'
character-set-server = utf8mb4
symbolic-links=0
local-infile=0
skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 32M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
#innodb_use_native_aio = 0
innodb_file_per_table
max_connections=200
max_user_connections=50
wait_timeout=10
interactive_timeout=50
long_query_time=5
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/

View File

@@ -0,0 +1,49 @@
[client]
port=3306
socket=/run/mysqld/mysqld.sock
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld_safe]
socket=/run/mysqld/mysqld.sock
[mysqld]
user=mysql
pid-file=/run/mysqld/mysqld.pid
socket=/run/mysqld/mysqld.sock
port=3306
basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
lc-messages-dir=/usr/share/mysql
log_error=/var/log/mysql/error.log
collation-server = utf8mb4_unicode_520_ci
init-connect='SET NAMES utf8mb4'
character-set-server = utf8mb4
symbolic-links=0
local-infile=0
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 16M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
#innodb_use_native_aio = 0
innodb_file_per_table
max_connections=70
max_user_connections=30
wait_timeout=10
interactive_timeout=50
long_query_time=5
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/

View File

@@ -0,0 +1,49 @@
[client]
port=3306
socket=/run/mysqld/mysqld.sock
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld_safe]
socket=/run/mysqld/mysqld.sock
[mysqld]
user=mysql
pid-file=/run/mysqld/mysqld.pid
socket=/run/mysqld/mysqld.sock
port=3306
basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
lc-messages-dir=/usr/share/mysql
log_error=/var/log/mysql/error.log
collation-server = utf8mb4_unicode_520_ci
init-connect='SET NAMES utf8mb4'
character-set-server = utf8mb4
symbolic-links=0
local-infile=0
skip-external-locking
key_buffer_size = 16K
max_allowed_packet = 1M
table_open_cache = 10
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 240K
#innodb_use_native_aio = 0
innodb_file_per_table
max_connections=30
max_user_connections=20
wait_timeout=10
interactive_timeout=50
long_query_time=5
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/

View File

@@ -0,0 +1,39 @@
# Implement TLS 1.3 0-RTT anti-replay for NGINX
# Requires: NGINX directive "ssl_early_data" on
# Usage:
# Make sure these "map" blocks are included in "http" block
# Put the following two lines in SSL "server" block, before any "location" blocks
# if ($anti_replay = 307) { return 307 https://$host$request_uri; }
# if ($anti_replay = 425) { return 425; }
# Pass "Early-Data" header to backend/upstream
# Only for 0-RTT requests from clients that understand 425 status code (RFC 8470)
# fastcgi_param HTTP_EARLY_DATA $rfc_early_data if_not_empty;
# proxy_set_header Early-Data $rfc_early_data;
# Copyright © myrevery
# Copyright © 7677333 (An anagram of a Anonymous Cybersecurity Research Team)
map "$request_method:$is_args" $ar_idempotent {
default 0;
"~^GET:$|^(HEAD|OPTIONS|TRACE):\?*$" 1;
}
map $http_user_agent $ar_support_425 {
default 0;
"~Firefox/((58|59)|([6-9]\d)|([1-9]\d{2,}))\.\d+" 1;
}
map "$ssl_early_data:$ar_idempotent:$ar_support_425" $anti_replay {
1:0:0 307;
1:0:1 425;
}
map "$ssl_early_data:$ar_support_425" $rfc_early_data {
1:1 1;
}

View File

@@ -0,0 +1,16 @@
map $http_user_agent $mobile_request {
default desktopversion;
"~*ipad" mobileversion;
"~*android.*mobile" mobileversion;
"~*iphone" mobileversion;
"~*ipod.*mobile" mobileversion;
"~*BlackBerry*Mobile Safari" mobileversion;
"~*BB*Mobile Safari" mobileversion;
"~*Opera.*Mini/7" mobileversion;
"~*IEMobile/10.*Touch" mobileversion;
"~*IEMobile/11.*Touch" mobileversion;
"~*IEMobile/7.0" mobileversion;
"~*IEMobile/9.0" mobileversion;
"~*Firefox.*Mobile" mobileversion;
"~*webOS" mobileversion;
}

View File

@@ -0,0 +1,130 @@
# Server globals
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /etc/nginx/conf.d/main/*.conf;
include /etc/nginx/modules-enabled/*.conf;
# Worker config
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
# Main settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
client_header_timeout 180s;
client_body_timeout 180s;
client_header_buffer_size 2k;
client_body_buffer_size 256k;
client_max_body_size 1024m;
large_client_header_buffers 4 8k;
send_timeout 60s;
keepalive_timeout 30s;
keepalive_requests 10000;
reset_timedout_connection on;
server_tokens off;
server_name_in_redirect off;
server_names_hash_max_size 512;
server_names_hash_bucket_size 512;
charset utf-8;
# FastCGI settings
fastcgi_buffers 512 4k;
fastcgi_buffer_size 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_connect_timeout 30s;
fastcgi_read_timeout 300s;
fastcgi_send_timeout 180s;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s;
fastcgi_cache_background_update on;
fastcgi_cache_revalidate on;
# Proxy settings
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header Early-Data $rfc_early_data;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Set-Cookie;
proxy_buffers 256 4k;
proxy_buffer_size 32k;
proxy_busy_buffers_size 32k;
proxy_temp_file_write_size 256k;
proxy_connect_timeout 30s;
proxy_read_timeout 300s;
proxy_send_timeout 180s;
# Log format
log_format main '$remote_addr - $remote_user [$time_local] $request "$status" $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
log_format bytes '$body_bytes_sent';
log_not_found off;
access_log off;
# Mime settings
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Compression
gzip on;
gzip_vary on;
gzip_static on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_buffers 128 4k;
gzip_http_version 1.1;
gzip_types text/css text/javascript text/js text/plain text/richtext text/shtml text/x-component text/x-java-source text/x-markdown text/x-script text/xml image/bmp image/svg+xml image/vnd.microsoft.icon image/x-icon font/otf font/ttf font/x-woff multipart/bag multipart/mixed application/eot application/font application/font-sfnt application/font-woff application/javascript application/javascript-binast application/json application/ld+json application/manifest+json application/opentype application/otf application/rss+xml application/ttf application/truetype application/vnd.api+json application/vnd.ms-fontobject application/wasm application/xhtml+xml application/xml application/xml+rss application/x-httpd-cgi application/x-javascript application/x-opentype application/x-otf application/x-perl application/x-protobuf application/x-ttf;
gzip_proxied any;
# Cloudflare IPs
include /etc/nginx/conf.d/cloudflare.inc;
# SSL PCI compliance
ssl_buffer_size 1369;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256";
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_early_data on;
ssl_ecdh_curve auto;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:20m;
ssl_session_tickets on;
ssl_session_timeout 7d;
resolver 1.0.0.1 8.8.4.4 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
resolver_timeout 5s;
# Error pages
error_page 403 /error/404.html;
error_page 404 /error/404.html;
error_page 410 /error/410.html;
error_page 500 501 502 503 504 505 /error/50x.html;
# Proxy cache
proxy_cache_path /var/cache/nginx levels=2 keys_zone=cache:10m inactive=60m max_size=1024m;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_temp_path /var/cache/nginx/temp;
proxy_ignore_headers Cache-Control Expires;
proxy_cache_use_stale error timeout invalid_header updating http_502;
proxy_cache_valid any 1d;
# FastCGI cache
fastcgi_cache_path /var/cache/nginx/micro levels=1:2 keys_zone=microcache:10m inactive=30m max_size=1024m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503;
add_header X-FastCGI-Cache $upstream_cache_status;
# Cache bypass
map $http_cookie $no_cache {
default 0;
~SESS 1;
~wordpress_logged_in 1;
}
# File cache (static assets)
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors off;
# Wildcard include
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/conf.d/domains/*.conf;
}

Some files were not shown because too many files have changed in this diff Show More