Billionmail/BillionMail · error

failed to write postfix master config: %v

Error message

failed to write postfix master config: %v

What it means

Raised in SetPostfixMasterSSL when os.WriteFile fails to persist the edited Postfix master.cf (c.PostfixMasterConf path) after the smtpd_tls_auth_only/smtpd_tls_wrappermode substitutions succeeded. Typical causes: permission denial on the Postfix config path or a read-only filesystem; the SSL enable flow aborts before service restart.

Source

Thrown at core/internal/service/mail_service/certificate.go:181

	if err != nil {
		return fmt.Errorf("failed to read postfix master config: %v", err)
	}

	content, err = gregex.ReplaceString(`\n*#\s*-o\s+smtpd_tls_auth_only=yes`, "\n  -o smtpd_tls_auth_only=yes", content)

	if err != nil {
		return fmt.Errorf("failed to update postfix master config: %v", err)
	}

	content, err = gregex.ReplaceString(`\n*#\s*-o\s+smtpd_tls_wrappermode=yes`, "\\n  -o smtpd_tls_wrappermode=yes", content)

	if err != nil {
		return fmt.Errorf("failed to update postfix master config: %v", err)
	}

	// Update Postfix Master configuration
	if err := os.WriteFile(c.PostfixMasterConf, []byte(content), 0755); err != nil {
		return fmt.Errorf("failed to write postfix master config: %v", err)
	}

	return nil
}

// SetDovecotSSL configures SSL certificate for Dovecot
func (c *Certificate) SetDovecotSSL(csrPem, keyPem string) error {
	// Validate certificate data
	if err := c.verifyCertificate(csrPem, keyPem); err != nil {
		return err
	}

	// Update Dovecot configuration
	if err := c.updateDovecotConfig(csrPem, keyPem); err != nil {
		return err
	}

	// Restart Dovecot service

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Run the service with privileges to write master.cf (root or CAP_DAC_OVERRIDE in container)
  2. Ensure the postfix config volume is mounted read-write
  3. Check filesystem free space and mount flags (ro vs rw)
  4. Consider writing atomically (temp file + rename) and matching mode 0644 typical for master.cf instead of 0755
Defensive patterns

Strategy: validation

Validate before calling

cfPath := consts.POSTFIX_MASTER_CONF
if err := os.MkdirAll(filepath.Dir(cfPath), 0755); err != nil { return err }
test, err := os.OpenFile(cfPath, os.O_WRONLY, 0)
if err != nil {
    return fmt.Errorf("cannot write %s: %w (need root or rw mount)", cfPath, err)
}
test.Close()

Try / catch

if err := certService.SetPostfixMasterSSL(); err != nil {
    if strings.Contains(err.Error(), "failed to write postfix master config") {
        if isReadOnly(strings Dir(cfPath)) { remountOrRelaunchWithWriteAccess() }
        return err
    }
    return err
}

Prevention

When it happens

Trigger: os.WriteFile to c.PostfixMasterConf fails: read-only filesystem, missing directory, or insufficient permissions (app not running as root).

Common situations: App container without write access to /etc/postfix; master.cf mounted read-only in Docker; disk full on the config volume.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/75414c00e8f17f48. Report an issue: GitHub.