P1
Storage AWS

Plik 1.4.2 on AWS User Guide

| Product: Plik 1.4.2 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Plik 1.4.2 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg File Sharing and Sync listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Plik is a self hosted temporary file sharing service. You upload one or more files in its web interface, with its API or with a small command line client, and get a short link to share. Every upload has an expiry (up to 30 days by default) after which Plik deletes it. Uploads can also be one shot (deleted after the first download), streamed (sent straight from the uploader to the downloader without being stored), protected by a password, or carry a Markdown comment. Your files stay on your own instance.

The cloudimg image adds:

  • Uploads need an account. Upstream Plik accepts uploads from anyone by default. This image forces authentication: only signed in users and API tokens can upload, and there is no self registration (the administrator creates accounts). Download links still work for anyone who has them.
  • An administrator unique to your instance. The first boot creates the database, the admin account (Plik generates its password) and an API token, and writes them to /root/plik-credentials.txt (readable by root only). Nothing is baked into the image; the web sessions are signed with a key generated on your instance.
  • HTTPS from the first boot. nginx serves Plik on port 443 with a certificate generated on your instance; port 80 redirects to HTTPS. Requests for a host name the instance does not serve get no answer. Share links use the configured host name, never one taken from a request.
  • Built from source with current dependencies. The upstream 1.4.2 server binary was built with Go 1.26.1 and carries 75 known vulnerabilities in the Go standard library and its modules. This image compiles Plik 1.4.2 from its source with Go 1.27.3 and the fixed releases of golang.org/x/net, golang.org/x/crypto, gRPC, pgx and others, and rebuilds the web interface with fixed releases of Mermaid and DOMPurify (which render the Markdown comments on download pages). The web interface loads no fonts or scripts from other sites. The build record is in /usr/share/doc/plik/BUILD-PROVENANCE.txt.
  • Hardened defaults. Plik listens on 127.0.0.1 only and runs as its own unprivileged user under a locked down systemd unit. Plik and nginx are blocked from the instance metadata service and the AMI requires IMDSv2. The client address Plik records comes from the connection, never from a header a client can forge. Uploaded HTML, SVG and script files are always downloaded, never rendered in the browser.
  • Files on their own volume. Uploads and Plik's database live on a separate 30 GiB EBS volume mounted at /var/lib/plik, which you can make bigger at launch or later.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Plik 1.4.2 (/opt/plik/plikd and its web interface), the Plik bash client for download, nginx, SQLite (Plik's database is a local file, so there is no database port), Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
  • A security group that allows TCP 443 (the web interface, uploads and share links) and TCP 80 (redirects to HTTPS) from the people who will use the service, and TCP 22 (SSH) from your own networks only.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Plik 1.4.2 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (Plik is light; a smaller type works for a small team), your key pair and a security group as above.

The AMI has two volumes: the 8 GiB root volume (/dev/sda1) and the 30 GiB data volume (/dev/sdf) that holds every upload. Set the data volume to the space you expect to share; Plik accepts files of up to 10 GB each by default.

With the AWS CLI (replace the values in angle brackets; this launch makes the data volume 100 GiB):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --block-device-mappings 'DeviceName=/dev/sdf,Ebs={VolumeSize=100,VolumeType=gp3}' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=plik}]'

If you make the data volume bigger than 30 GiB, grow its file system once after the first boot (Step 11).

Step 2: Connect to your instance

Version SSH user
Plik 1.4.2 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot takes a few seconds. Then Plik, nginx and the first boot unit are active:

systemctl is-active plik nginx plik-firstboot
active
active
active

nginx is the only web listener; Plik itself listens on 127.0.0.1 only:

sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|plikd/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN 127.0.0.1:8080 users:(("plikd"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))

The number of nginx entries follows the number of vCPUs. The server reports the release and the Go toolchain it was built with:

/opt/plik/plikd --version
plikd version 1.4.2 built from git rev ed7f43fb [release] at <build time> UTC with go1.27.3 linux/amd64

Step 4: Get your URL, password and API token

sudo cat /root/plik-credentials.txt

The file holds the address Plik is served as (your instance's public IP address by default), the administrator password and the API token generated on this instance:

# Plik 1.4.2 - generated on first boot by plik-firstboot.service. Unique to this instance; keep it safe.

plik.url=https://<public-ip>/

# Web UI login (Sign in, then Admin to add users):
plik.admin.user=admin
plik.admin.pass=<32 letters and digits>

# API token for scripts and the bash client (HTTP header "X-PlikToken: <token>"):
plik.api.token=<token>

# Uploads need a login or a token (anonymous uploads are disabled). Download links work for anyone who has them.
# Change the host name:  sudo plik-set-host <dns-name>
# Change the admin password: in the web UI (Admin > Users > admin > Edit), then update this file.

Plik's settings are in /etc/plik/plikd.cfg. The first boot set the address used in share links (PlikDomain); authentication is forced and Plik listens on 127.0.0.1:

sudo grep -E '^(ListenAddress|ListenPort|PlikDomain|SourceIpHeader|FeatureAuthentication|FeatureLocalLogin|FeatureApiTokens|MaxFileSizeStr|DefaultTTLStr|MaxTTLStr)' /etc/plik/plikd.cfg
ListenAddress       = "127.0.0.1"
ListenPort          = 8080
PlikDomain          = "https://<public-ip>"
SourceIpHeader      = "X-Real-IP"
MaxFileSizeStr      = "10GB"
DefaultTTLStr       = "30d"
MaxTTLStr           = "30d"
FeatureAuthentication = "forced"
FeatureLocalLogin     = "enabled"
FeatureApiTokens      = "enabled"

Step 5: Sign in

Open plik.url in your browser. The certificate is self signed (generated on your instance), so accept the browser warning once, or use your own name and certificate (Step 10). Choose Login and sign in as admin with plik.admin.pass:

The Plik sign in page with Login and Password fields and a Sign in button

Step 6: Upload and share files

The Upload page takes files by drag and drop, paste or a file picker. Before uploading, choose the options you want: destruct after download (one shot), streaming, removable by the downloader, end to end encryption, a password, a Markdown comment, and how long the upload is kept:

The Plik Upload page with the upload settings (destruct after download, streaming, removable, end-to-end encryption, password, comment), an expiration of 30 days and the drop zone

After the upload Plik shows the upload's page: the share link, the admin link (which lets you add or delete files later), the comment and each file with its own link:

The Plik upload page for the Q3 board pack with its expiry, share and admin links, a Markdown comment with a Draft, Review, Approved diagram, and three files: q3-revenue.csv, board-presentation.pdf and agenda.txt

Anyone with the share link sees the files and can download them, without an account. The upload disappears when it expires (or after the first download, for a one shot upload):

The same upload opened from its share link by someone who is not signed in: the comment, the three files with View and Download buttons, a zip archive button and a QR code, but no admin actions

Step 7: Your uploads, tokens and users

Your name at the top right opens your account: Uploads lists everything you have shared (with remove buttons), Tokens lists your API tokens and creates new ones, and Edit account changes your password:

The Plik account page for admin with the Uploads tab: a one shot upload holding install.log and the Q3 board pack upload with three files, each with its expiry and a Remove button

Admin shows the server's statistics, every upload and the users. There is no self registration, so add an account for each person who should upload with Create User, and change the administrator password with Edit on the admin row (then update plik.admin.pass in /root/plik-credentials.txt):

The Plik Admin page, Users tab: the server is v1.4.2 built with go1.27.3, one user admin (local, Administrator) with an Edit button, and a Create User button

Step 8: Upload from scripts

Every upload needs a token or a session. Send the token in the X-PlikToken header and keep it out of the command line by reading the header from a file. On the instance:

sudo sed -n 's/^plik.api.token=/X-PlikToken: /p' /root/plik-credentials.txt > ~/.plik-token && chmod 600 ~/.plik-token
H=$(sudo sed -nE 's#^plik.url=https://([^/]+)/.*#\1#p' /root/plik-credentials.txt)
echo "hello from Plik" > hello.txt
UP=$(curl -sk --resolve "$H:443:127.0.0.1" -H @"$HOME/.plik-token" -H 'Content-Type: application/json' -d '{"ttl":86400}' "https://$H/upload")
ID=$(echo "$UP" | jq -r .id)
curl -sk --resolve "$H:443:127.0.0.1" -H @"$HOME/.plik-token" -F "file=@hello.txt" "https://$H/file/$ID" | jq -r '"https://'"$H"'/file/'"$ID"'/" + .id + "/" + .fileName'

The last command prints the direct download link of the file, for example https://<public-ip>/file/<upload-id>/<file-id>/hello.txt; the upload's page is https://<public-ip>/#/?id=<upload-id>. From your own computer use the same calls without --resolve, with -k until you install a trusted certificate (Step 10).

The image also serves Plik's bash client (it uses curl) at https://<public-ip>/clients/bash/plik.sh. Run it on your own computer (Linux or macOS) with the server address in PLIK_URL and the token in ~/.plikrc:

curl -k -o plik.sh https://<public-ip>/clients/bash/plik.sh
printf 'Token = "%s"\n' '<plik.api.token>' > ~/.plikrc && chmod 600 ~/.plikrc
PLIK_URL=https://<public-ip> bash plik.sh -k -t 1d report.pdf
Create new upload on https://<public-ip>...

 --> https://<public-ip>/#/?id=<upload-id>

Uploading files...

curl -s 'https://<public-ip>/file/<upload-id>/<file-id>/report.pdf' > 'report.pdf'

The client prints the upload's link and a download command for each file. -k accepts the self signed certificate (drop it once you install a trusted one, Step 10), -o makes the upload one shot, -c "<text>" adds a comment, and bash plik.sh -h lists every option. The Go command line client (plik) is not included in this image; download it from the Plik releases if you want it, and point it at your server with the same token.

Step 9: Check the security model

The image ships a self test that proves the credential model over HTTPS: an anonymous upload is refused, the API token uploads a file that an anonymous downloader gets back byte for byte (the test upload is then removed), the administrator password signs in and a wrong one is refused:

sudo /usr/local/sbin/plik-selftest
OK: anonymous upload refused; token upload + anonymous download round-trip over TLS; admin login works, wrong password 403

Plain HTTP redirects to HTTPS, uploads and the user list refuse you without credentials, and a request for a host name the instance does not serve gets no answer:

H=$(sudo sed -nE 's#^plik.url=https://([^/]+)/.*#\1#p' /root/plik-credentials.txt)
curl -s -o /dev/null -w 'plain HTTP: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -w '\nanonymous upload: %{http_code}\n' --resolve "$H:443:127.0.0.1" -X POST -H 'Content-Type: application/json' -d '{}' "https://$H/upload"
curl -sk -o /dev/null -w 'user list without a session: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/users"
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: evil.example' http://127.0.0.1/ || true
plain HTTP: 301 -> https://<public-ip>/
unable to create upload : anonymous uploads are disabled
anonymous upload: 400
user list without a session: 401
unknown host name: 000

Plik and nginx cannot reach the instance metadata service; nginx passes Plik the address of the connection, overwriting any forwarded address a client sends; the secrets are readable by root (or Plik's own user) only:

systemctl show plik nginx -p Id -p IPAddressDeny
grep -E 'proxy_set_header (Host|X-Real-IP|X-Forwarded-For)' /etc/nginx/plik-proxy.conf
sudo stat -c '%a %U:%G %n' /root/plik-credentials.txt /etc/plik/plikd.cfg /var/lib/plik/plik.db /etc/nginx/ssl/plik.key
IPAddressDeny=169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
Id=plik.service

IPAddressDeny=169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
Id=nginx.service
proxy_set_header Host $plik_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
600 root:root /root/plik-credentials.txt
640 root:plik /etc/plik/plikd.cfg
640 plik:plik /var/lib/plik/plik.db
600 root:root /etc/nginx/ssl/plik.key

The certificate was generated on this instance and names its own addresses:

H=$(sudo sed -nE 's#^plik.url=https://([^/]+)/.*#\1#p' /root/plik-credentials.txt)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN = <public-ip>, O = cloudimg
X509v3 Subject Alternative Name:
    IP Address:<public-ip>, DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost

Step 10: Your own DNS name and certificate

Point a DNS record at the instance, then set the name Plik is served as. This mints a new self signed certificate for the name, updates nginx, Plik's PlikDomain (the address in share links) and the URL in /root/plik-credentials.txt, restarts Plik and keeps the name across reboots:

sudo plik-set-host <your-domain>

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx (running plik-set-host again replaces it with a self signed one):

sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/plik.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/plik.key
sudo nginx -t && sudo systemctl reload nginx

Step 11: Storage

Uploads (/var/lib/plik/files) and Plik's SQLite database (/var/lib/plik/plik.db) are on the data volume:

df -h /var/lib/plik
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme1n1     30G  3.4M   28G   1% /var/lib/plik

To make it bigger, increase the volume's size in the EC2 console (Volumes, Modify volume) or with aws ec2 modify-volume, then grow the file system online. The device name can differ between instance types, so take it from findmnt:

sudo resize2fs "$(findmnt -no SOURCE /var/lib/plik)"

Plik can also keep files in S3 or an S3 compatible store (DataBackend = "s3" with an Endpoint, Bucket, AccessKeyID and SecretAccessKey in [DataBackendConfig] of /etc/plik/plikd.cfg; see the Plik documentation). It needs an access key for the bucket: an EC2 instance role is not used, because Plik's S3 client takes static keys only and this image blocks Plik from the instance metadata service. Create an IAM user limited to the one bucket, then restart Plik with sudo systemctl restart plik.

Step 12: Server components

Component Path
Plik server (built from source with Go 1.27.3) /opt/plik/plikd
Web interface, bash client, release notes /opt/plik/webapp/dist, /opt/plik/clients/bash/plik.sh, /opt/plik/changelog
Configuration /etc/plik/plikd.cfg (root:plik, 0640)
Uploaded files and SQLite database (data volume) /var/lib/plik
systemd unit plik.service (user plik, 127.0.0.1:8080)
nginx site /etc/nginx/sites-available/cloudimg-plik
Certificate and key /etc/nginx/ssl/
First boot script /usr/local/sbin/plik-firstboot.sh
Host name helper /usr/local/sbin/plik-set-host
Self test /usr/local/sbin/plik-selftest
Credentials /root/plik-credentials.txt (mode 0600)
Licence and build record /usr/share/doc/plik/LICENSE, /usr/share/doc/plik/BUILD-PROVENANCE.txt

Back up /var/lib/plik (stop Plik first, or snapshot the data volume) and /etc/plik/plikd.cfg. Plik deletes expired uploads by itself.

Plik's own command line administration works through the same configuration file, as the plik user. For example, to list the users:

sudo -u plik /opt/plik/plikd --config /etc/plik/plikd.cfg user list

Step 13: Security recommendations

  • Allow port 22 in the security group from your own networks only; open 80 and 443 only to the people who should use the service.
  • Keep the administrator password and the API token private; change the password (Step 7) and revoke and recreate the token on the Tokens page if they may have leaked.
  • Use your own DNS name and a certificate your users trust (Step 10), so nobody learns to click through certificate warnings.
  • Keep the expiry short, and use one shot uploads or a password for anything sensitive.
  • Keep the operating system patched; unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else.

Support and licensing

Plik is free software under the MIT licence; a copy is at /usr/share/doc/plik/LICENSE. This image runs the unmodified Plik 1.4.2 source from https://github.com/root-gg/plik, built with the newer dependency versions listed in /usr/share/doc/plik/BUILD-PROVENANCE.txt (and without the web interface's links to Google Fonts). There is no per user or per CPU licence fee. The AMI price covers cloudimg's hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA