Skip to content

Linger v0.5.0

Latest

Choose a tag to compare

@github-actions github-actions released this 12 Oct 03:08
8454b7e

Linger 0.5.0: reactions, polls, talking from inside a game, and a sturdier server

The biggest release so far. Reactions are back, the way Discord and Slack do
them. The host can ask a room a question with /poll. Push-to-talk works
with a game in front. You can leave a group DM. The crackle at the start of
every sentence in voice is fixed for real this time. And before the release,
the app and the server went through an audit for safety and speed: about
forty fixes came out of it, from a tiny picture that could stop a server to a
minimized window that kept drawing for nobody.

Everyone: update the app. The voice fix is in the app that's listening,
and most new things need the new app.

Hosts: update the server, and read For hosts
first.
This update has more steps than usual. It changes the database,
so going back to 0.4.10 means restoring the copy update.sh makes. If you
run the voice relay, you need the new compose.yaml and more ports open, in
that order.
Most of the new things need the server as well as the app.

The highlights

  • Reactions are back (#485). A small pill under a message with the emoji
    and how many people left it. Any emoji, six different ones on a message at
    most, and they never notify anybody.
  • Polls (#474). The host or a co-host types /poll in a room, and
    everybody votes with a click.
  • Push-to-talk works with a game in front (#500), on Windows and Linux,
    and with Linger minimized or in the tray.
  • No more crackle at the start of a sentence (#470). 0.4.10's fix was
    aimed at the wrong cause. This one found the real one.
  • Leave a group DM (#565), and nobody can put you back.
  • A forgotten password has a way back (#581): the host makes a sign-in
    link in the app. No more stopping the server.
  • The server backs itself up every night (#582), and tells the host when
    its disk is filling up.
  • Old files stay until the server needs the room (#583), instead of going
    after a year.

Reactions

  • Pills under a message (#485): other people's are grey, yours are blue
    with an outline. Click one to add yours, and click yours to take it back.
    Point at a pill to see who left it. On a phone, hold it (#573).
  • Any emoji, the server's own included. On a computer, point at a message
    and click the smiley beside its ⋯, or the smiley-plus after its reactions.
    On a phone, hold the message: it shows the six emoji you use most and a
    button for every emoji.
  • Six different reactions on a message at most.
  • Never a notification, a sound or a lit row.
  • The host can turn them off for a room (Settings → Hosting → Rooms →
    Edit → Reactions). They're hidden, not deleted. You can hide them for
    yourself
    in Settings → Appearance → Show reactions. DMs always have them.
  • Removing one of the server's own emoji removes the reactions made with it.
  • Friends on 0.4.10 or older don't see reactions until they update. On a
    server that hasn't updated, the app shows no reaction buttons.

Polls

  • Asking (#474). The host or a co-host types /poll in a room's message
    box, with the question after it if they like, and presses Enter. A panel
    opens: two to ten choices, whether people can pick more than one, and when
    it closes (a day to four weeks; a week to start with). Nothing is posted
    until Post poll. Rooms only, not DMs.
  • Voting. Everybody votes with a click, the person who asked included.
    Click another choice to move your vote, or yours to take it back, until it
    closes. You see the results before you vote, and votes aren't secret: each
    choice shows who picked it as dots in their colors.
  • Closing. It closes when its time is up, or when whoever asked presses
    Close poll. A quiet grey line at the bottom of the room then says what
    won, with See results.
  • It pokes nobody. A new poll makes the room look new, like anything
    said. No notification and no sound.
  • Every / command is the host's or a co-host's now. Anybody else's box
    says who can, and nothing is sent.
  • Friends on an older app see the question and its choices as a list.

In the room

  • "Jules joined voice" (#473). When somebody joins a room's voice and
    stays ten seconds, the room gets one quiet grey line, so people reading can
    see the talk moved to voice. Joins close together share one line. It's
    written at most once per person per room every ten minutes, and it never
    notifies. There's no line for leaving.
  • Fewer chimes (#473). Each person's join and leave chime plays at most
    once a minute, so somebody dropping in and out doesn't ring the room each
    time. Setting a message of the day no longer chimes either.
  • A time written with a zone reads in your own clock (#584). "8PM CDT"
    gets a faint dotted underline. Point at it, or tap it on a phone, and it
    says "9:00 PM for you". It works in messages, the message of the day and
    polls, old messages included. Short names that mean more than one place
    (CST, IST, BST) are left alone rather than guessed.
  • Your local time on your card, if you turn it on (#604): Settings →
    Profile → Show my local time. Friends see "3:12 AM for Jules" on your card
    and on your Knock button, so they know it's late before they knock. It
    starts off, and it follows the computer or phone you last opened Linger on.
    On a server that hasn't updated, the switch stays off and says "This server
    needs updating before it can show your time." (#640)

Group DMs

  • Leave a group DM (#565): the ⋯ on its row or in its header, then
    Leave this group…. It goes from your list on every device you're signed
    in on. The others get a quiet line, "Callie left". Asking for a DM with the
    same people again makes a new one, so nobody is pulled back in.
  • The last person out deletes it, messages and files, since nobody could
    ever read it again. The question says so first. Export before you leave if
    you want a copy.
  • A one-to-one DM can't be left: it's that friend's row.
  • Friends on an older app see "left" as an ordinary message from that person.

Push-to-talk with a game in front

  • The talk key works while another app is in front (#500), and with
    Linger minimized or in the tray, the way Discord does. Linger listens for
    that one key, and only while you're in voice with push to talk on. It sees
    no other key and sends nothing about your keys anywhere. The game still
    gets the key too.
  • Windows: it just works, and the key can be a mouse's middle or side
    button (Mouse 4, Mouse 5). A game run as administrator hides its keys from
    Linger, as it does from Discord.
  • Linux: your desktop hands Linger the key. KDE and GNOME ask which key
    the first time you join voice with push to talk on. On Hyprland (Omarchy
    included), Settings → Sound & Voice shows one line to add to your config.
    It needs Linger installed (the Arch package, .deb, .rpm or AppImage).
    The user guide has the details.
  • A Mac built from source asks macOS about the key the same way (#587). It
    hasn't been tried on a real Mac yet.
  • The tray icon shows you're in voice (#601). The door gets an amber
    microphone while your microphone is on, and a grey crossed-out one while
    you're muted or deafened. On Windows, pointing at it says where you are.

A forgotten password

  • The host makes a sign-in link (#581) in Settings → Hosting → People →
    Sign-in Links: pick the person, press Make a sign-in link, and send it
    the way you'd send an invite. It works once, for 24 hours. Only the host
    can make one, not a co-host, and nobody can make one for the host.
  • The friend pastes it into Server or link, chooses a new password, and
    is in. Every other place they were signed in is signed out.
  • Nobody is surprised. Their Settings → Account & App says a link was
    made for them, and when it was used. The sign-in screen now says "Forgot
    your password? Ask the host for a sign-in link".

Invite links in a browser

  • A page instead of an error (#578). A friend who opens an invite link
    before they have Linger used to get an empty error page. Now they see
    "You're invited to …", how long the invite has left, where to get Linger,
    and a Copy button. A used-up or expired invite says so. A setup link
    gets the same page, with a red "Don't share this link".
  • Open in Linger (#607). A friend who already has Linger gets a button
    on that page that opens the app with the invite in its box. They check the
    address and press Continue: nothing is contacted until they do. With an
    older app the button does nothing, so copy and paste the link as before.

Media and exports

  • Leaving soon (#583), a new filter in Media, shows which files would be
    cleared next, so you can star what you want to keep. While the server has
    plenty of room it shows nothing.
  • Exports open in any web browser (#585). Unzip and double-click Open
    me.html
    : every room and DM, laid out like Linger, with pictures, videos,
    sound, reactions and polls. It works offline, years from now. Each
    conversation is also there as a .json file, for programs.
  • An export's link lasts a week (#504), and the app says the date it
    stops working.

Voice

  • No crackle at the start of a sentence (#470). Everybody's first words
    had a little crackle, on any connection, a wired one included. 0.4.10
    blamed packets arriving late, and that was wrong. The real cause was the
    app's own queue of sound waiting to play: it slipped tiny bits of silence
    into the rising first syllable of nearly every sentence. Now it only adds
    silence where there already is some. The fix is in the app that's
    listening, so you hear clean voices once your own app is 0.5.0.
  • The microphone turns off when you're dropped from voice (#589). After
    the computer slept for more than two minutes, the server restarted, or you
    signed out, Linger showed you out of voice but kept the microphone open, so
    the system's mic light stayed on. It lets go now. Press Join to carry on.
    Signing out of a server while in voice there also leaves voice at once,
    rather than two minutes later.
  • A double-click on Join (#510) put you in voice deafened, because the
    second click landed on Deafen. A double-click now counts as one click, and a
    double-click on Leave no longer joins you straight back.

Safety

The audit looked for ways somebody could fool you or get at your things.
What it found, all fixed:

  • A link can't hide another link (#508). A link written inside another
    link's words opened both pages at once, and the hidden one ended up in
    front. Now it's one link, to where it really goes.
  • A link whose words name another site shows where it really goes (#580):
    www.paypal.com (evil.example), with the real site in grey beside it. A
    name spelled with look-alike letters from another alphabet shows its true
    form (xn--…). It works on old messages too, and in exports.
  • A file's name can't pretend to be something else (#488). Invisible
    characters that turn text around could make a program look like a PDF: a
    file named invoice, then one of those characters, then fdp.exe, showed
    as "invoiceexe.pdf". The server takes those characters out of file names,
    statuses, room names and topics, polls and the message of the day. Hebrew
    and Arabic still look as written.
  • Nobody can take a name that looks like someone else's (#574): matt
    beside Matt, a Cyrillic letter in place of a Latin one, rn for m. The
    name field says so. Names already in use aren't changed.
  • Changing your password signs you out everywhere else, at once (#496),
    a computer you forgot about included. The device you change it on stays
    signed in. Update the app before you change your password: on an
    updated server, an app from 0.4.10 or earlier can sign itself out right
    after the change, and you'd sign in again with the new password.
  • A deleted message's files go at once (#502). Before, a file's link kept
    working for up to six hours after its message was deleted.
  • Linux banners show a message's words as typed (#489). A message with
    <b> in it showed bold in the desktop banner, and on KDE could put a link
    there.

Safety on the server

These protect a host's server from a member, or a stranger, trying to break
it. They come with the server update.

  • One tiny picture could stop a server (#487). A 35-byte GIF claiming to
    be enormous made it run out of memory. Every picture now has a memory
    budget, and at most two are worked on at once. Very large progressive JPEGs
    and WebPs, and very long GIFs, now get "That image can't be read." When two
    big pictures are already being worked on, the next waits up to ten seconds,
    then says "The server is busy with other pictures. Send this one again in a
    moment."
  • Strangers can't make a server work hard on demand (#495, #546). Joining
    checks the invite before the password. At most four passwords are checked at
    once. Sign-ups from one network are limited, 60 an hour to start with. The
    limits can't be dodged with a made-up header or by hopping between IPv6
    addresses. Whoever meets a limit is told why, and how long to wait.
  • The voice relay carries voice to its own server and nowhere else
    (#501). Before, a member could use it to reach other things on the host's
    network.
  • The server's data is its own (#506). On a machine with more than one
    account, the others can't read the database, the files, the backups or
    .env.
  • One member can't fill the server's storage (#503). Each person can have
    1 GB going up at once. Space held by an upload that went quiet comes back
    after an hour, files uploaded but never sent go after a week, and removing
    somebody frees their space. Taking a file out of the message box while it's
    going up now stops it.
  • Smaller fixes: an upload to an S3 bucket can't be bigger than it said it
    was (#505); link previews can't reach private addresses dressed up as IPv6
    ones (#490); a connection that hasn't signed in can't send huge messages
    (#517); an away message has the same length limit everywhere (#497); one
    app can't flood a server with room moves, away changes or voice joins
    (#497, #527); export archives no longer pile up on the disk (#504); used
    sign-in tokens are deleted after 30 days (#520); a search with an invisible
    NUL character in it no longer fails (#498).
  • Behind the scenes: every tool the release build borrows is pinned to
    exact code, so nobody could swap one to sign a bad update (#491). The list
    window can't show a banner of its own around the app's rules (#548).

Speed and memory

In the app:

  • A smaller app (#521). The Linux program is 25 MB instead of 43 MB,
    and the phone's .apk is about a third smaller (13 MB instead of 20 MB).
  • How fast it opens is measured now: about a second (#591). Dates are
    made ready when one is shown, not every time a window opens (#535).
  • Less work while nothing happens. An open conversation no longer redraws
    its window every two seconds (#511). A window's sound shuts between sounds,
    instead of playing silence all day (#531). The Shimmer name costs about half
    as much (#532). On Windows, a minimized Linger, or one in the tray, stops
    drawing (#594).
  • Less work when something does happen (#533). Something on one server
    redraws that part of the list, not the whole list: a friend going away on
    another server draws 26 pieces instead of 202. Thirty servers can sign in
    at once without some of them failing to show.
  • No slow leak (#534). Switching conversations kept a little memory every
    time, about 6 MB per thousand switches. It lets go now.
  • The list asks each server for its name and color when it connects and then
    hourly, not every two minutes (#536). A host's own change still shows at
    once.

On the server:

  • Faster as it grows (#518). On a server with a year of messages,
    opening Media went from about 450 ms to 25 ms, and a search from about
    140 ms to 1 ms.
  • An idle server rests (#522). With nobody in voice, voice forwarding
    still woke 50 times a second. Now it waits for somebody to join.
  • Memory comes back after sign-ins (#523). Each password check borrows
    about 19 MB, and the server never gave it back. After 280 sign-ups it held
    1.9 GB; now it holds 21 MB.
  • Less memory for each person connected (#519). Each event is turned into
    text once and shared, rather than once per person.
  • Smaller cleanups from the same audit (#524).

Fixes

  • A room that came up empty after the computer woke (#468) now loads by
    itself, trying again for half a minute, and opening it again tries again.
  • The AppImage opened an empty window on newer graphics drivers (Mesa
    26.2, Omarchy with an AMD card, say) (#479). If yours did, download this
    release's AppImage by hand.
  • Linux: Linger could quit when a conversation opened beside the list
    (#628). Fixed.
  • Windows: an update could stop on "Error opening file for writing"
    (#568), when Windows happened to be reading the program right then. It now
    waits up to ten seconds and carries on.
  • One part that can't be drawn no longer blanks the whole window (#509).
    Its place says "This conversation couldn't be shown." with Try again,
    and everything else keeps working.
  • A new message is followed down (#625) when you were resting just short
    of the bottom, or a link card above was loading at that moment. It's marked
    read too.
  • Retry never posts a message twice (#524). When the answer to a send got
    lost after the server had saved it, Retry posted a copy, and a photo's Retry
    was refused. Polls the same. This needs the server update.
  • Phone photos show the right way up (#569). The server threw away the
    photo's "this way up" note along with its location. Photos already sent
    sideways stay sideways.
  • Pictures, pastes, knocks and dates (#512). A very tall picture, like a
    phone's scrolling screenshot, stays wide enough to see. A picture that can't
    load says so, with Load again. A paste over 8,000 characters says only
    the start fit. A second knock from one person replaces their first, and at
    most three knocks show at once. A message dated in the future, from a server
    whose clock runs ahead, shows its date. A message made only of invisible
    letters is refused, like an empty one.
  • At big interface sizes (150%, say), windows can't be dragged too small
    to type in (#512). A long name in wide letters no longer squeezes out "in
    #room", and emoji in a gradient name keep their own colors.
  • An export no longer fails for somebody with DMs with two people the host
    has since removed (#585).
  • Only words worth copying can be selected (#483): the conversation,
    people's cards, the message of the day, what you type, and errors. The list,
    labels and buttons can't, as in any desktop app. The message box's hint
    can't either (#478).

Under the hood

  • Releases are built with tauri-action 1.0, and latest.json still points at
    the normal download links (#597). A practice tag publishes no server image.
  • Every workflow action is pinned to a commit, and Dependabot proposes newer
    ones once a month (#491).
  • Tests that failed at random on a busy machine were each fixed for their own
    cause (#461, #525, #528, #559, #567, #572, #637).
  • scripts/tidy-branches.sh deletes finished branches (#472), and a new issue
    that arrives without a label gets one from its words (#481).
  • How fast Linger opens is measured in docs/performance.md (#591). Ambient
    voice (M13) is cut (#600).
  • The guides cover reactions (#537), and the VPS guide's firewall table opens
    UDP 3479 (#564).

Known issues

  • "App not installed" on Android when installing over a Linger that was
    signed differently, like a test build from a computer. Uninstall it once,
    which signs you out, then install this one. Releases install over each other.
  • Read positions don't move live between two devices that are both open.
    Read a room on the phone while the computer is open, and the computer shows
    it as new until it next connects afresh (a restart, say). Your own messages
    are fine either way.
  • The phone app doesn't update itself. Install each new .apk over the
    old one.
  • On Hyprland (Omarchy included), the mouse pointer jumps into a
    conversation that opens in a window of its own.
    The
    user guide has the two lines that turn it
    off.
  • The AppImage doesn't play AV1 videos (#358). Windows and the Arch,
    .deb and .rpm packages do.

For hosts: updating the server

Server image: ghcr.io/itsmattguenther/linger:0.5.0 (x86-64 only), also
tagged 0.5 and latest.

What changes for you

  • The database changes. Ten changes (0013 to 0024; 0021 and 0022 aren't
    used) run by themselves the first time 0.5.0 starts. That first start can
    take a second or two longer than usual, once. update.sh saves the
    database just before, and that copy is how you'd go back: 0.4.10 won't
    start on a database 0.5.0 has changed.
  • A new compose.yaml, which relay hosts need. It keeps the relay to
    voice for your own server (#501), and gives it 200 ports instead of 41, so
    a raid fits (#197). Those ports have to be open first (step 3).
  • Files stay longer. The new default is
    LINGER_FILE_EXPIRY_DAYS=when-full: nothing is deleted for being old. Once
    uploads fill 90% of LINGER_POOL_BYTES, the oldest unstarred files go until
    it's back under 80% (#583). Before, a file went a year after it was shared.
    For the old rule, put LINGER_FILE_EXPIRY_DAYS=365 in .env. If you had set
    a number already, nothing changes. On S3, the bucket now fills up to
    LINGER_POOL_BYTES before anything goes, and you pay for what's in it.
  • A copy of the database every night, into data/backups/ (#582). It
    keeps a week of nightly copies and a month of weekly ones. Each is about the
    size of your database (not the uploaded files), so it takes some disk. To
    stop it, if you already back up data another way, put
    LINGER_BACKUPS=off in .env. The copies are on the same disk as the
    server, so Backups in the host guide says how to
    keep one somewhere else too.
  • Lines for you at the foot of your list, seen by the host only: when the
    disk is nearly full, when files have used up their space and nothing is left
    that could go, or when the server hasn't backed up for three days.
    Settings → Hosting → Server says when the last copy was made.
  • New settings, all optional, all in the new .env.example. Leave them
    out and nothing changes:
    • LINGER_BACKUP_S3_* sends each night's copy to a bucket too, so it
      survives the machine (#614). The host guide's
      Sending the copies to a bucket
      says how.
    • LINGER_SIGNUPS_PER_HOUR (60 to start with) is how many people may sign
      up from one network in an hour. Raise it, or set it to off, before a big
      group joins together from one place (#495).
      A big group joining at once
      has the details.
    • LINGER_PASSWORD_CHECKS_AT_ONCE (4 to start with) is how many passwords
      the server checks at the same time. Each takes about 19 MB of memory and a
      processor core for a moment.
    • LINGER_TRUSTED_PROXIES (private to start with) is only for a proxy
      that isn't on this machine or a private network, like Caddy on a VPS
      reaching a home server over Tailscale: private,100.64.0.0/10. Behind
      such a proxy and without it, everybody shares one allowance for signing
      in
      , so one stranger could lock everyone out. The usual setup, Caddy next
      to Linger, needs nothing.
  • Sign-in links replace reset-password for a member who forgot their
    password: Settings → Hosting → People → Sign-in Links. reset-password on
    the machine stays your own way back into your own account.
  • What needs the server updated, not just the app: reactions, polls, the
    "joined voice" line, leaving a group DM, sign-in links, local time on your
    card, the invite page and Open in Linger, Leaving soon, the backup and disk
    lines, Retry never posting twice, and the week-long export link. Friends
    on older apps keep working with the new server; the new things show up for
    them as they update.
  • Changing a password on an older app. On this server, an app from 0.4.10
    or earlier can sign itself out right after its person changes their
    password. Signing in again with the new password fixes it. Nobody is signed
    out by the update itself.
  • Only the server can open the data folder now (#506). From an account
    other than root, ls data is refused. update.sh doesn't need to look
    inside: it copies the database out through a container, with no sudo.
    Its copies in backups/ are readable by you alone.
  • A deleted message's files go at once (#502), and files are now served
    as private to caches. Behind a caching proxy like Cloudflare's, files come
    from your server rather than the proxy, which uses a little more of your
    bandwidth.
  • On S3, add a cleanup rule that deletes anything under uploads/ after
    two days (#505). The host guide's
    Settings you might want to change
    says where that is on R2 and AWS.
  • Exports go a week after they're made, and straight away with a member
    you remove. A server short of disk refuses to build one rather than filling
    up (#504).
  • A new server set up with setup.sh takes its files from the newest
    release, so they match the server Docker downloads, rather than from
    main (#507).

The steps

Run these on the server, one block at a time, in this order. Each step
says why it's there. If you type sudo before docker commands, do the same
for every docker command and for ./update.sh below.

1. Go to your linger folder and keep copies of your files. If anything
goes wrong, these are how you put things back as they were.

cd ~/linger
cp compose.yaml compose.yaml.before-0.5.0
cp Caddyfile Caddyfile.before-0.5.0
cp .env .env.before-0.5.0
chmod 600 .env.before-0.5.0

(If your folder is somewhere else, cd to the one with your compose.yaml.)
chmod 600 keeps the copy of .env readable by you alone, since it holds the
relay's secret. If cp .env says there's no such file, that's fine: an older
server without the relay may not have one.

2. Find out where your settings are.

grep '^LINGER_DOMAIN=' .env
  • It prints your server's name, like LINGER_DOMAIN=linger.example.com.
    Your settings are in .env: you set up with setup.sh, or by hand from
    0.4.9. The new files can simply replace the old ones. Go on to step 3.
  • It prints nothing, or "No such file". Your settings are written inside
    compose.yaml, from a server set up before 0.4.9. The new compose.yaml
    reads every setting from .env, so putting it in place of yours as it is
    would lose your server's name and settings. You'll move them into .env in
    step 4, before anything replaces the old file.
    • No relay? Then you don't need the new files at all: your old
      compose.yaml keeps working with 0.5.0. Skip to step 5.

3. Run the voice relay? Open its new ports first. To see whether you run
it:

docker ps -a --format '{{.Names}}'

(Put sudo in front if you type it before docker commands.) If no name has
coturn in it, you don't run the relay: skip to step 4.

If you do, the new compose.yaml gives the relay UDP ports 49160 to
49359
, where it had 49160 to 49200. Open them before you get the new
file.
With the new compose.yaml and the old firewall, the relay hands most
of the people who need it a port your firewall drops, and they can't get into
voice. Everybody whose voice goes straight to your server is fine either way.

  • DigitalOcean: in the control panel, open Networking → Firewalls. If
    your droplet is in one of the firewalls listed (many droplets have none, and
    then there's nothing to do here), open it, and under Inbound Rules add a
    Custom rule: protocol UDP, port range 49160-49359, sources All
    IPv4
    and All IPv6. Save it. The old 49160-49200 rule can stay or go.

  • Another provider (Hetzner, Linode, AWS and the rest): the same in its
    firewall or security group. Allow inbound UDP 49160 to 49359.

  • At home: on your router, forward UDP 49160 to 49359 to the server, in
    the same place you forwarded 49160 to 49200 before.

  • On the server itself, whatever the provider:

    sudo ufw status

    Only if it says Status: active, run:

    sudo ufw allow 49160:49359/udp

    If it says inactive, there's nothing to do.

Last, check .env starts the relay with everything else:

grep '^COMPOSE_PROFILES=voice' .env

If that prints nothing, add the line once: echo COMPOSE_PROFILES=voice >> .env.

4. Get the new files. If step 2 found your settings inside
compose.yaml, follow
Moving an older server's settings into .env
in the host guide first. Where it says to download the files, use the
commands just below: they fetch 0.5.0's. Its first step, keeping copies of
the old files, you did in step 1. Then go on to step 5.

Everybody else:

curl -fLO "https://raw.githubusercontent.com/itsMattGuenther/Linger/v0.5.0/deploy/compose.yaml"
curl -fLO "https://raw.githubusercontent.com/itsMattGuenther/Linger/v0.5.0/deploy/Caddyfile"
curl -fLO "https://raw.githubusercontent.com/itsMattGuenther/Linger/v0.5.0/deploy/update.sh"
curl -fLO "https://raw.githubusercontent.com/itsMattGuenther/Linger/v0.5.0/deploy/.env.example"
chmod +x update.sh

They come from the 0.5.0 release, so they go with the server you're about to
get. Your .env isn't touched: .env.example only lists the new settings, as
comments. If you run the relay, this compose.yaml is also what keeps the
relay to voice (#501), so you need it even apart from the ports.

Did you pin a version? If you had changed the image: line to stay on a
version, the new file says latest again. Look at the old one:

grep 'image: ghcr' compose.yaml.before-0.5.0

If it ends in a version, like :0.4.10, open the new file with
nano compose.yaml and give its image: line a version the same way (:0.5.0
to take this one). Save with Ctrl+O, Enter, then Ctrl+X. Anything
else you had changed in the old compose.yaml by hand, a wider relay range
say, change in the new one too.

5. Update.

./update.sh

(Use sudo ./update.sh if you type sudo before docker commands.) It says
where voice goes, downloads 0.5.0 while the server keeps running, stops it for
a few seconds to save the database into backups/, then starts everything
again, the relay too, and prints the version before and after. The database
changes run then, by themselves. If 0.5.0 doesn't start, update.sh prints the
commands that put 0.4.10 back.

6. Check it worked.

docker compose ps

linger and caddy, and coturn if you run the relay, say Up. Wait about
30 seconds and run it again: still Up, not Restarting.

curl -f https://linger.example.com/api/v1/health

With your own address in place of linger.example.com, it prints
{"ok":true,"version":"0.5.0"}.

docker compose logs linger | grep 'voice forwarding'

It prints a line saying voice forwarding is on, with the address voice goes
to. (Nothing, if you set LINGER_VOICE_ADDRESS=off.)

If you run the relay:

docker compose --profile voice logs coturn | head -n 5
docker compose --profile voice logs --tail 20 coturn

One of the first lines says the relay carries voice to your server's public
address and nowhere else. The last lines shouldn't say it's stopping, or that
the secret is empty. If it says the relay carries nothing, or that DNS gave no
answer, The voice relay in the host guide
says what to do.

Then join voice from the app, with a friend on another network if you can,
and check you hear each other.

7. If something's wrong later: going back to 0.4.10. update.sh saved
the database into backups/ just before 0.5.0 started. Going back needs that
copy, because 0.4.10 won't start on a database 0.5.0 has changed. Anything
posted after the update is lost when you go back
: messages, people who
joined, rooms made. Files sent since then stay on the disk, but nothing points
at them. So decide soon if you're going to.

Go to your linger folder first:

cd ~/linger

If you type sudo before docker commands, run sudo -s now: it keeps you
in this folder, and exit when you're done gets you out again. Then find the
copy's name; the newest is at the top:

ls -t backups/

It looks like linger-0.4.10-2026-10-12-203000.tar.gz. Put its name in place
of NAME.tar.gz:

docker compose stop linger
docker compose run --rm --no-deps -T --user root --entrypoint sh linger -c 'cd /data && rm -f linger.db-wal linger.db-shm && tar xzf -' <backups/NAME.tar.gz
cp compose.yaml.before-0.5.0 compose.yaml
cp Caddyfile.before-0.5.0 Caddyfile
sed -i 's#ghcr.io/itsmattguenther/linger:latest#ghcr.io/itsmattguenther/linger:0.4.10#' compose.yaml
docker compose up -d

The second line puts the database copy back. It's the same command
update.sh prints when an update fails. The cp lines put your old files
back, and the sed line keeps you on 0.4.10, which docker compose up -d
downloads again. If your old file had a version on its image: line already,
the sed line changes nothing: open it with nano compose.yaml and make that
line image: ghcr.io/itsmattguenther/linger:0.4.10. If you moved your settings
or changed .env for this update, cp .env.before-0.5.0 .env puts it back
too. The relay goes back to its old rules and ports. Later, set the image:
line back to :latest to follow new releases again.

Install or update

Use the in-app update: Update… at the foot of the list, or Settings →
Account & App → Updates. Windows users should keep the same installer format
(.exe or .msi) when upgrading. Linux packages are .AppImage, .deb and
.rpm; on Omarchy or Arch, Linger updates with your system (Update in the
Omarchy menu, or sudo pacman -Syu). Windows installers are updater-signed,
not Authenticode-signed; SmartScreen may still warn about an unfamiliar app.
If the 0.4.10 AppImage opened an empty window for you (#479), download this
release's AppImage by hand.

On Android, download Linger_0.5.0_android-arm64.apk from this release on
the phone and install it over the old one. You stay signed in. A first install
is step by step in the 0.4.8 notes.

Older apps and servers mix fine. An app from 0.4.10 or earlier keeps
working with a 0.5.0 server, and 0.5.0 keeps working with an older server.
New things wait for the server: until it updates, there are no reaction
buttons and no Leaving soon, sign-in links and Show my local time say the
server needs updating, and polls and leaving a group DM are refused. Friends still on an older app see a
poll as its question and choices, "joined voice" and "left" as ordinary
messages, and no reactions. The one thing to avoid is changing your password
on an app older than 0.5.0 (see Safety).

New to Linger? Which file do I want?

Your computer Download the file ending in
Windows -setup.exe
Debian, Ubuntu or Mint .deb
Fedora, RHEL or openSUSE .rpm
Any other Linux .AppImage — make it executable and run it
macOS Not built yet — see decisions.md
Android phone _android-arm64.apk — download it on the phone
iPhone Not yet

The .msi is for companies rolling it out to many machines at once.
If you are not sure, you want the .exe.

The .sig files and latest.json are how an installed copy checks
that an update is genuine. You do not need to download them.

Windows will warn you. You get "Windows protected your PC", and
Run anyway is behind the small More info link. That is Windows
saying the installer has not been through a paid signing process. It
has not — that is a
known decision,
not a broken download.

Android will ask before installing. The phone says it won't
install apps from your browser until you allow it: tap Settings,
turn on Allow from this source, and go back. That is Android's
rule for any app that isn't from the Play Store. The phone app
doesn't update itself: install each new one from its release page,
right over the old one, and you stay signed in.

Checks on installed clients

Record OS, package type, previous and new version, and headset or microphone
with any failure. Use made-up messages, and keep private conversations out of
screenshots.

  1. Voice, the start of a sentence, with three or more people on 0.5.0,
    across two real networks if you can: pause, then talk again, a few times
    each. The first word comes through clean (#470).
  2. Push-to-talk on Windows, in voice with push to talk on: hold the key
    with a fullscreen game in front, then with Linger minimized, then with it
    in the tray. Try Mouse 4 as the key (#500).
  3. Push-to-talk on Omarchy with the Arch package: add the line Settings →
    Sound & Voice shows, then hold Right Ctrl with another app in front (#500).
  4. The tray icon, with the list in the tray: join voice (amber
    microphone), mute (grey), leave (the plain door) (#601).
  5. Sleep in voice: join, let the computer sleep more than two minutes,
    wake it. The system's mic light goes off and the tray icon is the plain
    door; Join brings you back (#589).
  6. Reactions: add, take back, point at a pill for names, six on one
    message. On the phone, hold a pill to see who left it (#485, #573).
  7. Polls, as the host: /poll, vote from several apps, close it, and let
    a one-day poll run out (#474).
  8. The joined-voice line: join and stay: one grey line. Join and leave a
    few times quickly: still one line, and one chime (#473).
  9. Leave a group DM on one device while it's open on another: its tab or
    window closes there, and the others see "left" (#565).
  10. A sign-in link: the host makes one, the friend pastes it and sets a
    new password, and their other devices are signed out (#581).
  11. Change a password on one device with the same account on another: the
    other is signed out within seconds, and the first stays in (#496).
  12. An invite link in a browser: the page shows, Copy works, and Open in
    Linger
    opens the app with the link in its box, on the Windows installer,
    on Android and on the Arch package (#578, #607).
  13. Windows, minimized: with a Shimmer name on screen, minimize Linger and
    check Task Manager; close it to the tray and bring it back a few times. It
    draws properly each time (#594, #532).
  14. Windows, the update itself: the in-app update from 0.4.10 finishes
    with no "Error opening file" box (#568).
  15. Linux: the AppImage on Mesa 26.2 with an AMD or Intel GPU shows the
    app (#479). In a package, open and close conversations beside the list
    many times: Linger stays open (#628).
  16. Export: export everything, unzip, and open Open me.html in a
    browser (#585).
  17. As a host who runs the relay: after the steps above, somebody whose
    network blocks UDP 3479 still gets into voice and is heard (#501, #197).