A newsletter you run on your own server

Docs

Install with Kamal

Kamal builds the image from your clone on your computer and deploys it to your server, so you can change the code. To run the ready-made image as one container without Kamal, install with Docker.

Paste this into your agent

Install Mailpiece on my server with Kamal. Read mailpiece.dev/llms.txt first.

What you need

A server you reach over SSH, with ports 80 and 443 open and a domain pointed at it, such as app.example.com. kamal setup installs Docker on it if it's missing, which works on Linux. The image is built for amd64; for an ARM server, set builder.arch in your destination file.

Mail. SMTP for the app's own mail, such as sign-in codes, and a provider or SMTP server for the newsletter's, set in the app on Settings › Outgoing mail. See Mail.

For Kamal, on your machine. Git, Docker to build the image and the Ruby in .ruby-version. No registry account is needed.

Get the code

git clone https://github.com/mailpiece/mailpiece.git
cd mailpiece
bundle install

Describe your server

config/deploy.yml is shared; yours goes in a destination file of your own name, so a pull never touches it. The proxy host and BASE_URL are the same address.

# config/deploy.production.yml
servers:
  web:
    hosts:
      - 203.0.113.10

volumes:
  - mailpiece_live:/rails/storage

proxy:
  ssl: true
  hosts:
    - app.example.com

ssh:
  user: root

env:
  clear:
    RAILS_ENV: production
    BASE_URL: https://app.example.com
    MAILER_FROM_ADDRESS: My Newsletter <[email protected]>

Set the secrets

Every secret config/deploy.yml lists goes in .kamal/secrets.production, read from your shell or a password manager. See Configuration.

Make SECRET_KEY_BASE once and keep it safe apart from the server: the relay token and SMTP password Mailpiece stores are encrypted with keys derived from it. A new one also signs everyone out, and the rating links in issues already mailed stop answering.

# Make SECRET_KEY_BASE once
openssl rand -hex 64

# .kamal/secrets.production
SECRET_KEY_BASE=$SECRET_KEY_BASE
SMTP_ADDRESS=$SMTP_ADDRESS
SMTP_USERNAME=$SMTP_USERNAME
SMTP_PASSWORD=$SMTP_PASSWORD
S3_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID
S3_ENDPOINT=$S3_ENDPOINT
S3_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY

Deploy

The first time, setup installs Docker on the server, builds the image, starts the app and gets the certificate. The databases are created on first start. Use setup this once; after, deploy.

Set up backups of the mailpiece_live volume.

bin/kamal setup -d production

Open it

Go to /signup, as in https://app.example.com/signup. Until the first account exists the sign-in code is shown on screen, so this works before mail is set up; after, it goes by email.

The first person is staff and sees the job queue at /admin/jobs. Signup closes after the first account unless MULTI_TENANT is true; a signed-in person can still start another newsletter from the account menu.

Update it

Your destination file and its secrets are git-ignored, so a pull never touches them.

git pull
bin/kamal deploy -d production

More than one environment

Each is another destination: config/deploy.<name>.yml, with its secrets in .kamal/secrets.<name>.

bin/kamal deploy -d <name>

Day to day

bin/kamal console -d production
bin/kamal shell -d production
bin/kamal logs -d production

Then

Take your first steps.

Still need help? Ask on GitHub.