Official Docker image for PeakURL, a self-hosted URL shortener.
- Image:
peakurl/peakurl - Source: PeakURL/containers
- Core app: PeakURL/PeakURL
- Issues: PeakURL/containers/issues
- Learn More: PeakURL Docker Documentation
- Supported architectures:
linux/amd64,linux/arm64 - Tag style: version tags such as
1.0.12, semver aliases such as1.0and1, pluslatest
Use an exact version tag when you want a repeatable deployment.
PeakURL lets you run your own branded short links with analytics, a dashboard, and a self-hosted PHP application you control.
This image packages the public PeakURL release archive and is intended for:
- a simple Docker Compose deployment
- a
docker rundeployment - a reverse-proxy setup behind Nginx, Apache, Traefik, or another SSL terminator
Pull the image:
docker pull peakurl/peakurl:latestRecommended layout on a server:
/var/www/sites/data/www/example.com/
├── compose.yaml
└── data/
├── mysql/
└── peakurl/
Edit the values in compose.yaml before you start the stack:
- set
APACHE_SERVER_NAMEto your real public short domain - review the
127.0.0.1:8080:80port mapping and keep it on localhost if a host reverse proxy will forward traffic - set the MySQL credentials in the
dbservice - keep the PeakURL installer defaults in the
peakurlservice aligned with the MySQL values - pin
PEAKURL_IMAGE_TAGto an exact version if you want repeatable deploys
Example compose.yaml:
services:
peakurl:
# Pin an exact tag when you want repeatable deployments.
image: docker.io/peakurl/peakurl:${PEAKURL_IMAGE_TAG:-latest}
restart: unless-stopped
environment:
TZ: UTC
# Change this to your real public short domain.
APACHE_SERVER_NAME: example.com
PEAKURL_INSTALL_DB_HOST_DEFAULT: db
PEAKURL_INSTALL_DB_PORT_DEFAULT: "3306"
# Keep these installer defaults aligned with the MySQL service below.
PEAKURL_INSTALL_DB_NAME_DEFAULT: peakurl
PEAKURL_INSTALL_DB_USER_DEFAULT: peakurl
PEAKURL_INSTALL_DB_PASSWORD_DEFAULT: change-this-password
ports:
# Keep this on localhost if a host reverse proxy will forward traffic.
# <Host IP>:<Host Port>:<Container Port>
- "127.0.0.1:8080:80"
volumes:
# Keep the full PeakURL app tree beside the compose file.
- "./data/peakurl:/var/www/html"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/ >/dev/null || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
db:
image: mysql:8.4
restart: unless-stopped
environment:
# Change these database values before you deploy.
MYSQL_DATABASE: peakurl
MYSQL_USER: peakurl
MYSQL_PASSWORD: change-this-password
MYSQL_ROOT_PASSWORD: change-this-root-password
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-name-resolve
volumes:
# Keep database data beside the compose file by default.
- "./data/mysql:/var/lib/mysql"
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -p$$MYSQL_ROOT_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30sCreate the directories first:
mkdir -p data/peakurl data/mysqlStart it with:
docker compose up -dThen open http://127.0.0.1:8080 and complete the installer.
If you already run Nginx or Apache on the host, keep the bind address on
127.0.0.1 and proxy your public domain to http://127.0.0.1:8080.
If you want to expose the container directly instead, publish a normal host
port such as 8080:80.
This default layout keeps the app files and MySQL data beside the
compose file, so each site folder stays self-contained and does not need a
separate .env file.
On first start, the container copies the bundled PeakURL release into
./data/peakurl and then runs directly from that directory. This keeps the
folder structure the same as the release ZIP.
Create a deployment folder first:
mkdir -p peakurl-stack/data/peakurl peakurl-stack/data/mysql
cd peakurl-stack
docker network create peakurlStart MySQL:
docker run -d \
--name peakurl-db \
--network peakurl \
-e MYSQL_DATABASE=peakurl \
-e MYSQL_USER=peakurl \
-e MYSQL_PASSWORD=change-this-password \
-e MYSQL_ROOT_PASSWORD=change-this-root-password \
-v "$PWD/data/mysql:/var/lib/mysql" \
mysql:8.4 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--skip-name-resolveThen start PeakURL:
docker run -d \
--name peakurl \
--network peakurl \
-p 127.0.0.1:8080:80 \
-e APACHE_SERVER_NAME=example.com \
-e PEAKURL_INSTALL_DB_HOST_DEFAULT=peakurl-db \
-e PEAKURL_INSTALL_DB_PORT_DEFAULT=3306 \
-e PEAKURL_INSTALL_DB_NAME_DEFAULT=peakurl \
-e PEAKURL_INSTALL_DB_USER_DEFAULT=peakurl \
-e PEAKURL_INSTALL_DB_PASSWORD_DEFAULT=change-this-password \
-v "$PWD/data/peakurl:/var/www/html" \
peakurl/peakurl:latestThen open http://127.0.0.1:8080 and finish the installer.
PeakURL serves plain HTTP inside the container. SSL should be terminated by your existing reverse proxy or load balancer.
Example host-side configs are included here:
Typical proxy target:
http://127.0.0.1:8080- or another localhost port you published for the container
For Docker Compose, edit the values directly in compose.yaml.
The main values most users change are:
APACHE_SERVER_NAME- the published host port in
ports MYSQL_DATABASEMYSQL_USERMYSQL_PASSWORDMYSQL_ROOT_PASSWORD- the matching
PEAKURL_INSTALL_DB_*defaults
By default the Compose setup keeps data in local folders beside the compose file:
./data/peakurlmaps to/var/www/htmland stores the full PeakURL app tree./data/mysqlmaps to/var/lib/mysqlfor the MySQL database
On first boot, ./data/peakurl is populated from the bundled release package,
so files like content/languages/* stay exactly where the ZIP ships them.
If you prefer Docker-managed named volumes instead, you can replace those bind mounts in your own compose file.
For Docker Compose:
docker compose pull
docker compose up -dFor docker run, pull the new image and recreate the container with the same
volume and environment settings.
When a new PeakURL release is published, a matching container image is published separately. Existing containers keep running their current image tag until you pull the new tag and recreate them.
Because this image stores the full app tree in ./data/peakurl, pulling a new
image does not replace app files that already exist in that mounted directory.
For a fresh app tree from a newer image, back up your site first, then recreate
or clear ./data/peakurl before starting the updated container.
PeakURL is released under the MIT License.