Skip to content

Commit

Permalink
Merge pull request #123 from liberu-control-panel/sweep/Implement-ema…
Browse files Browse the repository at this point in the history
…il-server-management-functionality

Implement email server management functionality
  • Loading branch information
curtisdelicata authored Aug 31, 2024
2 parents 4d982d3 + 9b4846b commit 195e2e8
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 44 deletions.
14 changes: 10 additions & 4 deletions app/Filament/App/Resources/DomainResource/ContainerRestarter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

namespace App\Filament\Admin\Resources\DomainResource;

class DomainContainerRestarter
use Symfony\Component\Process\Process;

class ContainerRestarter
{
public function restart(string $domainName): void
public function restart(): void
{
// Restart necessary containers for the given domain
$process = new Process(['docker-compose', 'restart', $domainName]);
// Restart Postfix and Dovecot containers
$process = new Process(['docker-compose', 'restart', 'postfix', 'dovecot']);
$process->setWorkingDirectory(base_path());
$process->run();

if (!$process->isSuccessful()) {
throw new \RuntimeException('Failed to restart containers: ' . $process->getErrorOutput());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ class DovecotConfigGenerator
{
public function generate(string $email, string $password): string
{
return "user $email {\n password = $password\n}\n";
$domain = explode('@', $email)[1];
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

return <<<EOT
mail_location = maildir:/var/mail/$domain/$email
namespace inbox {
inbox = yes
}
protocol lda {
postmaster_address = postmaster@$domain
}
auth_mechanisms = plain login
passdb {
driver = passwd-file
args = scheme=CRYPT username_format=%u /etc/dovecot/users
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/%d/%n
}
service auth {
unix_listener auth-userdb {
mode = 0600
user = vmail
}
}
$email:{CRYPT}$hashedPassword
EOT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@ class PostfixConfigGenerator
{
public function generate(string $email, string $password): string
{
return "$email $password\n";
$domain = explode('@', $email)[1];
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

return <<<EOT
# Virtual domain configuration
virtual_mailbox_domains = $domain
virtual_mailbox_base = /var/mail
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
# SASL authentication
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
# TLS parameters
smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
# Virtual mailbox
$email $domain/$email/
# User authentication
$email:$hashedPassword
EOT;
}
}
47 changes: 29 additions & 18 deletions app/Filament/App/Resources/EmailResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,21 @@ public static function getPages(): array
protected function handleRecordCreation(array $data): Email
{
$email = Email::create($data);

// Generate Dovecot configuration
$dovecotConfig = $this->generateDovecotConfig($email->email, $email->password);
Storage::disk('dovecot')->put($email->email, $dovecotConfig);
Storage::disk('dovecot_config')->put($email->email . '.conf', $dovecotConfig);

// Generate Postfix configuration
$postfixConfig = $this->generatePostfixConfig($email->email, $email->password);
Storage::disk('postfix')->put($email->email, $postfixConfig);

Storage::disk('postfix_config')->put($email->email . '.cf', $postfixConfig);

// Create mailbox directory
Storage::disk('dovecot_data')->makeDirectory($email->email);

// Update Dovecot and Postfix Docker instances
$this->callSilent('email-servers:update');
$this->updateEmailServers();

return $email;
}

Expand All @@ -85,33 +88,41 @@ protected function handleRecordUpdate(Email $email, array $data): Email
$email->update($data);

// Update Dovecot configuration
$dovecotConfig = $this->generateDovecotConfig($email);
Storage::disk('dovecot')->put($email->email, $dovecotConfig);
$dovecotConfig = $this->generateDovecotConfig($email->email, $email->password);
Storage::disk('dovecot_config')->put($email->email . '.conf', $dovecotConfig);

// Update Postfix configuration
$postfixConfig = $this->generatePostfixConfig($email);
Storage::disk('postfix')->put($email->email, $postfixConfig);
$postfixConfig = $this->generatePostfixConfig($email->email, $email->password);
Storage::disk('postfix_config')->put($email->email . '.cf', $postfixConfig);

// Restart Dovecot and Postfix containers
$this->restartContainers();
// Update Dovecot and Postfix Docker instances
$this->updateEmailServers();

return $email;
}

protected function handleRecordDeletion(Email $email)
{
// Remove Dovecot configuration
Storage::disk('dovecot')->delete($email->email);
Storage::disk('dovecot_config')->delete($email->email . '.conf');

// Remove Postfix configuration
Storage::disk('postfix')->delete($email->email);
// Remove Postfix configuration
Storage::disk('postfix_config')->delete($email->email . '.cf');

// Restart Dovecot and Postfix containers
$this->restartContainers();
// Remove mailbox directory
Storage::disk('dovecot_data')->deleteDirectory($email->email);

// Update Dovecot and Postfix Docker instances
$this->updateEmailServers();

$email->delete();
}

protected function updateEmailServers()
{
$this->callSilent('email-servers:update');
}

protected function generateDovecotConfig(string $email, string $password): string
{
return (new DovecotConfigGenerator)->generate($email, $password);
Expand Down
49 changes: 29 additions & 20 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,36 @@ services:
environment:
- NGINX_PROXY_CONTAINER=nginx-proxy

postfix:
image: boky/postfix
restart: always
environment:
- SMTP_SERVER=example.com
- [email protected]
- SMTP_PASSWORD=password
ports:
- "25:25"
- "587:587"
version: '3'

dovecot:
image: dovecot/dovecot
restart: always
ports:
- "110:110"
- "143:143"
- "993:993"
- "995:995"
volumes:
- ./mail:/var/mail
services:
postfix:
image: postfix:latest
volumes:
- ./postfix_data:/var/spool/postfix
- ./postfix_config:/etc/postfix
environment:
- MAILNAME=example.com
ports:
- "25:25"
- "587:587"

dovecot:
image: dovecot:latest
volumes:
- ./dovecot_data:/var/mail
- ./dovecot_config:/etc/dovecot
ports:
- "110:110"
- "143:143"
- "993:993"
- "995:995"

volumes:
postfix_data:
postfix_config:
dovecot_data:
dovecot_config:

bind9:
image: internetsystemsconsortium/bind9:9.16
Expand Down

0 comments on commit 195e2e8

Please sign in to comment.