{"id":133,"date":"2019-06-02T18:00:25","date_gmt":"2019-06-02T17:00:25","guid":{"rendered":"https:\/\/blog.inplico.uk\/?p=133"},"modified":"2023-06-15T21:44:12","modified_gmt":"2023-06-15T20:44:12","slug":"postfix","status":"publish","type":"post","link":"https:\/\/blog.inplico.uk\/?p=133","title":{"rendered":"Postfix"},"content":{"rendered":"<p><strong>Installation<\/strong><\/p>\n<p>Now that we have postfixadmin and the database set up we can install postfix.<\/p>\n<pre class=\"lang:sh decode:true\">#apt-get install postfix-pgsql<\/pre>\n<p>NOTE: At this point there is a chance that Debian has pre-empted you and automatically installed a number of packages that you do not want and that conflict with the packages that you intend to use (I love Debian but its \u201cnanny knows best\u201d approach really pisses me off sometimes). If it does then you will need to run<\/p>\n<pre class=\"lang:sh decode:true\">#apt-get install postfix postfix-pgsql<\/pre>\n<p>This will probably bring up a window for configuration of exim4 even though it is going to remove it rather than install it; just humour it by excepting the defaults and let it do its thang!<\/p>\n<p>After this you can run autoremove if you want to get rid of the mysql stuff that debian thinks that you are going to need<\/p>\n<pre class=\"lang:sh decode:true\">#apt-get autoremove<\/pre>\n<p>We are going to store the mail in a custom location or \/home\/mailstore so we need to create that directory and set the permissions on it.<\/p>\n<p>First though we are going to add a user and a group called mailer<\/p>\n<pre class=\"lang:sh decode:true\">#groupadd mailer\r\n#useradd mailer \u2013g mailer<\/pre>\n<p>now we can create the directory and set the permissions<\/p>\n<pre class=\"lang:sh decode:true\">#mkdir \/home\/mailstore\r\n#chown mailer:mailer \/home\/mailstore<\/pre>\n<p>The other thing that we need to do is obtain the userid and groupid for the mailer user and group so that we can use them in the configuration file<\/p>\n<pre class=\"lang:sh decode:true\">#id mailer<\/pre>\n<p>should return something like<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">uid=1001(mailer) gid=1001(mailer) groups=1001(mailer)<\/pre>\n<p>so we now know that the user and group id\u2019s are 1001<\/p>\n<p><strong>Postfix Configuration<\/strong><\/p>\n<p><strong>master.cf<\/strong><\/p>\n<p>Postfix has two main config files: <strong>main.cf<\/strong>, which specifies what you would think of as config options, and <strong>master.cf<\/strong>, which specifies the services postfix should run.<\/p>\n<p>First, configure the <strong>master.cf<\/strong> file (in \/etc\/postfix\/). Add an extra &#8220;smtpd&#8221; instance called &#8220;submission&#8221; that will take mail from trusted clients for delivery to the world at large, which we don&#8217;t allow for anyone else.\u00a0 To do that, open master.cf (take a look at <a href=\"http:\/\/www.postfix.org\/master.5.html\">man 5 master<\/a> if you want to understand what&#8217;s going on) and uncomment the submission config and add options to enable SASL:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">submission inet n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 smtpd\r\n-o syslog_name=postfix\/submission\r\n-o smtpd_tls_wrappermode=no\r\n-o smtpd_tls_security_level=encrypt\r\n-o smtpd_sasl_auth_enable=yes\r\n-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination\r\n-o milter_macro_daemon_name=ORIGINATING\u00a0\u00a0\r\n-o smtpd_sasl_type=dovecot\u00a0\u00a0\r\n-o smtpd_sasl_path=private\/auth<\/pre>\n<p><strong>Note <\/strong>there are 2 spaces prepending the \u201c-o\u201d, these are necessary for the configuration to load<\/p>\n<p>taken from https:\/\/kuther.net\/howtos\/soho-mailserver-postfix-postgresql-dovecot-spamassassin-roundcube<\/p>\n<p>This warrants a bit of explanation. The -o &#8230; options override the settings that are taken from defaults or define in the config, which we&#8217;ll set later.<br \/>\nIn a nutshell what happens here is that this enables the &#8220;submission&#8221; daemon with TLS to secure the outer connection, and dovecot-mediated SASL to check the username and password of connecting clients. (We will set that up in dovecot later).<\/p>\n<p>The important detail is smtpd_recipient_restrictions which is missing <a href=\"http:\/\/www.postfix.org\/postconf.5.html#reject_unauth_destination\">reject_unauth_destination<\/a>, this is what restricts relaying.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>main.cf<\/strong><\/p>\n<p>That is it for master.cf, now we want to configure main.cf. Let&#8217;s first set the network information: (information about the domains postfix is handling mail for, and a bit of extra info)<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">myhostname = fqdn.suffix\r\nmyorigin = \/etc\/mailname\r\nmydestination = fqdn.suffix, domain.com, localhost,\r\nlocalhost.localdomain\r\nrelayhost =\r\nmynetworks = 127.0.0.0\/8\r\n[::ffff:127.0.0.0]\/104 [::1]\/128\r\nmailbox_size_limit = 0\r\nrecipient_delimiter = +\r\ninet_interfaces = all<\/pre>\n<p>We set the hostname and the default origin, which is sourced from <strong>\/etc\/mailname<\/strong> by debian convention. You can set it explicitly if you don&#8217;t have <strong>\/etc\/mailname<\/strong>. The default origin is used to construct the &#8216;From&#8217; address for local users. <strong>mydestination<\/strong> sets the domains that postfix accepts emails for as final destination, and we set &#8220;relayhost&#8221; empty to disable relaying mail (relaying means accepting mail and then forwarding to a mail server that is not the final destination for the mail and we have no need for that; that is useful e.g. in a corporate intranet where a central mail server should check mail before it leaves the network.)<\/p>\n<p>Now we need to set up the virtual mail for postgresql and dovecot transport. Depending on how your server is setup you might want to keep mail in a non default location. If possible I like to make a separate partition to store mail on, but if that is not possible then I will use the \/home directory. Whatever directory is used, it needs to be set in the virtual_mailbox_base directive<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">virtual_mailbox_base = \/home\/mailstore<\/pre>\n<p>virtual_mailbox_limit sets the maximum size of the mailbox, here we have it set to 5gig because space is not really a concern<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">virtual_mailbox_limit = 512000000<\/pre>\n<p>In a moment we are going to create some files that we will use to drag information from the postfix database. The following directives tell postfix what type of database we are connecting to, what the files are called, and their locations.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">virtual_mailbox_domains = proxy:pgsql:\/etc\/postfix\/pgsql\/virtual_domains_maps.cf\r\nvirtual_mailbox_maps = proxy:pgsql:\/etc\/postfix\/pgsql\/virtual_mailbox_maps.cf\r\nvirtual_alias_maps = proxy:pgsql:\/etc\/postfix\/pgsql\/virtual_alias_maps.cf<\/pre>\n<p>virtual_uid_maps and virtual_gid_maps are what we use to set the user and group ids of the user that has read write access to the mailstore. Earlier we used \u201cid mailer\u201d to obtain the gid and uid and discovered that in this particular instance they were both 1001 so we can set them her<\/p>\n<pre class=\"lang:monkey highlight:0 decode:true\">virtual_uid_maps = static:1001\r\nvirtual_gid_maps = static:1001<\/pre>\n<p>The only other settings are<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">virtual_minimum_uid = 8\r\ninet_protocols = ipv4<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>pgsql config files<\/strong><\/p>\n<p>As mentioned earlier in the postfixadmin configuration section, postfix uses the postgresql database tables that are managed with postfixadmin to gather the information it needs to operate correctly. The way that it does this is by running a series of SELECT statements depending on its needs. Unfortunately these statements need to be configured manually.<\/p>\n<p>The first thing we need to do is create a folder to store these files in called pgsql<\/p>\n<pre class=\"lang:sh decode:true \">#mkdir \/etc\/postfix\/pgsql<\/pre>\n<p>Once we have done that, we can create each of these files in the directory.<\/p>\n<p>Create \/etc\/postfix\/pgsql\/relay_domains.cf and add the following to it<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">user = postfixro\r\npassword = changeme\r\nhosts = localhost\r\ndbname = postfix\r\nquery = SELECT domain FROM domain WHERE domain='%s' and backupmx = true<\/pre>\n<p>Note that this is where we use the postfixro user as we only need read only access, if we are connecting to a remote host then its fqdn will need to be put in the hosts directive. The rest of these files should not require any further explanation as it is only the SQL statement that differs.<\/p>\n<p>Create \/etc\/postfix\/pgsql\/virtual_alias_maps.cf<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">user = postfixro\r\npassword = secret\r\nhosts = localhost\r\ndbname = postfix\r\nquery = SELECT goto FROM alias WHERE address='%s' AND active = true<\/pre>\n<p>Create \/etc\/postfix\/pgsql\/virtual_domains_maps.cf<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">user = postfixro\r\npassword = secret\r\nhosts = localhost\r\ndbname = postfix\r\nquery = SELECT domain FROM domain WHERE domain='%s' and backupmx = false and active = true<\/pre>\n<p>Create \/etc\/postfix\/pgsql\/virtual_mailbox_limits.cf<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">user = postfixro\r\npassword = secret\r\nhosts = localhost\r\ndbname = postfix\r\nquery = SELECT quota FROM mailbox WHERE username='%s'<\/pre>\n<p>Create \/etc\/postfix\/pgsql\/virtual_mailbox_maps.cf<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">user = postfixro\r\npassword = secret\r\nhosts = localhost\r\ndbname = postfix\r\nquery = SELECT maildir FROM mailbox WHERE username='%s' AND active = true<\/pre>\n<p>There is no need to alter the permissions on any of the files. Once this is done you should have fully configured postfix.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Troubleshooting<\/strong><\/p>\n<pre class=\"lang:sh decode:true\">#service postfix status<\/pre>\n<p>Use this to check the status of postfix<\/p>\n<pre class=\"lang:sh decode:true\">#postconf<\/pre>\n<p>This checks that the configuration is valid, note that it does not check that the configuration is correct, only that it could be valid, but it is still useful to check for syntax errors. Note that postconf can be used to alter settings, but this is beyond the scope of this manual.<\/p>\n<p><strong>From the man page<\/strong>: By default, the postconf(1) command displays the values of main.cf configuration parameters, and warns about possible mis-typed parameter names (Postfix 2.9 and later). It can also change main.cf configuration parameter values, or display other configuration information about the Postfix mail system.<\/p>\n<pre class=\"lang:sh decode:true\">#tail \u2013f \/var\/log\/mail.log<\/pre>\n<p>Use this command to monitor the log file to check for errors<\/p>\n<pre class=\"lang:sh decode:true\">#psql -U postfixro -d postfix\r\n\r\npostfix# SELECT * FROM mailbox<\/pre>\n<p>This can be used to check that your user can query the database. I had to edit pg_hba.conf to allow local access and when I tested it I could not select so had to run the following command on the database:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">GRANT SELECT ON ALL TABLES IN SCHEMA public TO postfixro<\/pre>\n<p><strong>Reverse PTR record<\/strong><\/p>\n<p>If your ISP is useless then getting them to assign a reverse PTR record for your given domain is slim to 0.\u00a0 The only way around this is to find the hostname that they have assigned to your ip and use that in your postfix configuration.\u00a0 First thing to do is<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">dig -x XXX.XXX.XXX.XXX<\/pre>\n<p>where xxx.xxx.xxx.xxx is your service provider&#8217;s assigned static ip address<\/p>\n<p>The reverse lookup should return a domain name in the answer section<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">static-xxx-xxx-xxx-xxx.vodafonexdsl.co.uk<\/pre>\n<p>You will need to then edit your \/etc\/postfix\/main.cf file so that it uses this domain name for both the banner and the HELO name. To do that go ahead and open main.cf with your favourite editor and add the line:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">smtp_helo_name = static-xxx-xxx-xxx-xxx.vodafonexdsl.co.uk<\/pre>\n<p>You will also need to change the banner to match:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">#smtpd_banner = $myhostname ESMTP $mail_name (Debian\/GNU)\r\nsmtpd_banner = static-xxx-xxx-xxx-xxx.vodafonexdsl.co.uk<\/pre>\n<p>Comment out the existing line and add a new one for your isp assigned hostname.\u00a0 This does not affect how you connect to your mail server, you can carry on using whatever you used previously, it is simply a workaround for poor service from your internet service provider.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Installation Now that we have postfixadmin and the database set up we can install postfix. #apt-get install postfix-pgsql NOTE: At this point there is a chance that Debian has pre-empted you and automatically installed a number of packages that you do not want and that conflict with the packages that you intend to use (I [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-133","post","type-post","status-publish","format-standard","hentry","category-debian-server"],"_links":{"self":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=133"}],"version-history":[{"count":3,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/133\/revisions"}],"predecessor-version":[{"id":400,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/133\/revisions\/400"}],"wp:attachment":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}