├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── config └── shlink_in_docker.local.php ├── docker-entrypoint.sh └── hooks └── build /.gitignore: -------------------------------------------------------------------------------- 1 | params 2 | data 3 | docker-compose.yml 4 | shlink*dist.zip 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: minimal 3 | 4 | services: 5 | - docker 6 | 7 | git: 8 | depth: 5 9 | 10 | script: 11 | - docker build -t shlink-docker-image:temp . 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.3.8-cli-alpine3.10 2 | LABEL maintainer="Alejandro Celaya " 3 | 4 | ARG SHLINK_VERSION=1.18.0 5 | ENV SHLINK_VERSION ${SHLINK_VERSION} 6 | ENV APCu_VERSION 5.1.16 7 | ENV APCuBC_VERSION 1.0.4 8 | ENV SWOOLE_VERSION 4.3.3 9 | 10 | WORKDIR /etc/shlink 11 | 12 | RUN \ 13 | 14 | # Install common php extensions 15 | docker-php-ext-install -j"$(nproc)" pdo_mysql calendar && \ 16 | 17 | # Install sqlite 18 | apk add --no-cache sqlite-libs sqlite-dev && \ 19 | docker-php-ext-install -j"$(nproc)" pdo_sqlite && \ 20 | 21 | # Install postgre 22 | apk add --no-cache postgresql-dev && \ 23 | docker-php-ext-install -j"$(nproc)" pdo_pgsql && \ 24 | 25 | # Install other PHP packages that depend on other system packages 26 | apk add --no-cache icu-dev && \ 27 | docker-php-ext-install -j"$(nproc)" intl && \ 28 | 29 | apk add --no-cache libzip-dev zlib-dev libpng-dev && \ 30 | docker-php-ext-install -j"$(nproc)" zip gd 31 | 32 | # Install APCu 33 | RUN wget "https://pecl.php.net/get/apcu-${APCu_VERSION}.tgz" -O /tmp/apcu.tar.gz && \ 34 | mkdir -p /usr/src/php/ext/apcu && \ 35 | tar xf /tmp/apcu.tar.gz -C /usr/src/php/ext/apcu --strip-components=1 && \ 36 | docker-php-ext-configure apcu && \ 37 | docker-php-ext-install -j"$(nproc)" apcu && \ 38 | rm /tmp/apcu.tar.gz 39 | 40 | # Install APCu-BC extension 41 | RUN wget "https://pecl.php.net/get/apcu_bc-${APCuBC_VERSION}.tgz" -O /tmp/apcu_bc.tar.gz && \ 42 | mkdir -p /usr/src/php/ext/apcu-bc && \ 43 | tar xf /tmp/apcu_bc.tar.gz -C /usr/src/php/ext/apcu-bc --strip-components=1 && \ 44 | docker-php-ext-configure apcu-bc && \ 45 | docker-php-ext-install -j"$(nproc)" apcu-bc && \ 46 | rm /tmp/apcu_bc.tar.gz 47 | 48 | # Load APCU.ini before APC.ini 49 | RUN rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini && \ 50 | echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini 51 | 52 | # Install swoole 53 | # First line fixes an error when installing pecl extensions. Found in https://github.com/docker-library/php/issues/233 54 | RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS && \ 55 | pecl install swoole-${SWOOLE_VERSION} && \ 56 | docker-php-ext-enable swoole && \ 57 | apk del .phpize-deps 58 | 59 | # Install shlink 60 | RUN wget https://github.com/shlinkio/shlink/releases/download/v${SHLINK_VERSION}/shlink_${SHLINK_VERSION}_dist.zip -O /tmp/shlink.zip && \ 61 | unzip /tmp/shlink.zip -d /etc/shlink && \ 62 | mv shlink_${SHLINK_VERSION}_dist/* . && \ 63 | rm -rf shlink_${SHLINK_VERSION}_dist && \ 64 | rm -f /tmp/shlink.zip 65 | 66 | # Add shlink to the path to ease running it after container is created 67 | RUN ln -s /etc/shlink/bin/cli /usr/local/bin/shlink 68 | 69 | # Add shlink in docker config to the project 70 | COPY config/shlink_in_docker.local.php config/autoload/shlink_in_docker.local.php 71 | 72 | # Expose swoole port 73 | EXPOSE 8080 74 | 75 | # Expose params config dir, since the user is expected to provide custom config from there 76 | VOLUME /etc/shlink/config/params 77 | 78 | COPY docker-entrypoint.sh docker-entrypoint.sh 79 | ENTRYPOINT ["/bin/sh", "./docker-entrypoint.sh"] 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2019 shlinkio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :warning: This project is deprecated :warning: 2 | 3 | Shlink's docker image configiration is now part of shlink's [main repository](https://github.com/shlinkio/shlink). 4 | 5 | Read [the docs](https://github.com/shlinkio/shlink/blob/master/docker/README.md) there in order to know how to use the image. 6 | -------------------------------------------------------------------------------- /config/shlink_in_docker.local.php: -------------------------------------------------------------------------------- 1 | 'pdo_mysql', 24 | 'postgres' => 'pdo_pgsql', 25 | ]; 26 | private const DB_PORTS_MAP = [ 27 | 'mysql' => '3306', 28 | 'postgres' => '5432', 29 | ]; 30 | 31 | /** @var string */ 32 | private $charset; 33 | /** @var string */ 34 | private $secretKey; 35 | 36 | public function __construct() 37 | { 38 | [$this->charset, $this->secretKey] = $this->initShlinkKeys(); 39 | } 40 | 41 | private function initShlinkKeys(): array 42 | { 43 | $keysFile = sprintf('%s/shlink.keys', sys_get_temp_dir()); 44 | if (file_exists($keysFile)) { 45 | return explode(',', file_get_contents($keysFile)); 46 | } 47 | 48 | $keys = [ 49 | env('SHORTCODE_CHARS', $this->generateShortcodeChars()), 50 | env('SECRET_KEY', $this->generateSecretKey()), 51 | ]; 52 | 53 | file_put_contents($keysFile, implode(',', $keys)); 54 | return $keys; 55 | } 56 | 57 | private function generateShortcodeChars(): string 58 | { 59 | return str_shuffle(self::BASE62); 60 | } 61 | 62 | private function generateSecretKey(): string 63 | { 64 | return substr(str_shuffle(self::BASE62), 0, 32); 65 | } 66 | 67 | public function getShortcodeChars(): string 68 | { 69 | return $this->charset; 70 | } 71 | 72 | public function getSecretKey(): string 73 | { 74 | return $this->secretKey; 75 | } 76 | 77 | public function getDbConfig(): array 78 | { 79 | $driver = env('DB_DRIVER'); 80 | if ($driver === null || $driver === 'sqlite') { 81 | return [ 82 | 'driver' => 'pdo_sqlite', 83 | 'path' => 'data/database.sqlite', 84 | ]; 85 | } 86 | 87 | $driverOptions = $driver !== 'mysql' ? [] : [ 88 | // PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', 89 | 1002 => 'SET NAMES utf8', 90 | ]; 91 | return [ 92 | 'driver' => self::DB_DRIVERS_MAP[$driver], 93 | 'dbname' => env('DB_NAME', 'shlink'), 94 | 'user' => env('DB_USER'), 95 | 'password' => env('DB_PASSWORD'), 96 | 'host' => env('DB_HOST'), 97 | 'port' => env('DB_PORT', self::DB_PORTS_MAP[$driver]), 98 | 'driverOptions' => $driverOptions, 99 | ]; 100 | } 101 | 102 | public function getNotFoundConfig(): array 103 | { 104 | $notFoundRedirectTo = env('NOT_FOUND_REDIRECT_TO'); 105 | 106 | return [ 107 | 'enable_redirection' => $notFoundRedirectTo !== null, 108 | 'redirect_to' => $notFoundRedirectTo, 109 | ]; 110 | } 111 | }; 112 | 113 | return [ 114 | 115 | 'config_cache_enabled' => false, 116 | 117 | 'app_options' => [ 118 | 'secret_key' => $helper->getSecretKey(), 119 | 'disable_track_param' => env('DISABLE_TRACK_PARAM'), 120 | ], 121 | 122 | 'delete_short_urls' => [ 123 | 'check_visits_threshold' => true, 124 | 'visits_threshold' => (int) env('DELETE_SHORT_URL_THRESHOLD', 15), 125 | ], 126 | 127 | 'translator' => [ 128 | 'locale' => env('LOCALE', 'en'), 129 | ], 130 | 131 | 'entity_manager' => [ 132 | 'connection' => $helper->getDbConfig(), 133 | ], 134 | 135 | 'url_shortener' => [ 136 | 'domain' => [ 137 | 'schema' => env('SHORT_DOMAIN_SCHEMA', 'http'), 138 | 'hostname' => env('SHORT_DOMAIN_HOST', ''), 139 | ], 140 | 'shortcode_chars' => $helper->getShortcodeChars(), 141 | 'validate_url' => (bool) env('VALIDATE_URLS', true), 142 | 'not_found_short_url' => $helper->getNotFoundConfig(), 143 | ], 144 | 145 | 'logger' => [ 146 | 'handlers' => [ 147 | 'shlink_rotating_handler' => [ 148 | 'level' => Logger::EMERGENCY, // This basically disables regular file logs 149 | ], 150 | 'shlink_stdout_handler' => [ 151 | 'class' => StreamHandler::class, 152 | 'level' => Logger::INFO, 153 | 'stream' => 'php://stdout', 154 | 'formatter' => 'dashed', 155 | ], 156 | ], 157 | 158 | 'loggers' => [ 159 | 'Shlink' => [ 160 | 'handlers' => ['shlink_stdout_handler'], 161 | ], 162 | ], 163 | ], 164 | 165 | 'dependencies' => [ 166 | 'aliases' => env('REDIS_SERVERS') === null ? [] : [ 167 | 'lock_store' => 'redis_lock_store', 168 | ], 169 | ], 170 | 171 | 'redis' => [ 172 | 'servers' => env('REDIS_SERVERS'), 173 | ], 174 | 175 | ]; 176 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -e 3 | 4 | cd /etc/shlink 5 | rm -f data/cache/app_config.php 6 | 7 | echo "Creating fresh database if needed..." 8 | if [ -f "./module/CLI/src/Command/Db/CreateDatabaseCommand.php" ]; then 9 | php bin/cli db:create -n -q 10 | else 11 | # Ignore the error when creating the database, since it could already exist 12 | php vendor/doctrine/orm/bin/doctrine.php orm:schema-tool:create -n -q >/dev/null 2>/dev/null || true 13 | fi 14 | 15 | echo "Updating database..." 16 | if [ -f "./module/CLI/src/Command/Db/MigrateDatabaseCommand.php" ]; then 17 | php bin/cli db:migrate -n -q 18 | else 19 | php vendor/doctrine/migrations/bin/doctrine-migrations.php migrations:migrate -n -q 20 | fi 21 | 22 | echo "Generating proxies..." 23 | php vendor/doctrine/orm/bin/doctrine.php orm:generate-proxies -n -q 24 | 25 | # When restarting the container, swoole might think it is already in execution 26 | # This forces the app to be started every second until the exit code is 0 27 | until php vendor/zendframework/zend-expressive-swoole/bin/zend-expressive-swoole start; do sleep 1 ; done 28 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | get_latest_release() { 5 | curl --silent "https://api.github.com/repos/shlinkio/shlink/releases/latest" | # Get latest release from GitHub api 6 | grep '"tag_name":' | # Get tag line 7 | sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value 8 | } 9 | 10 | if [[ ${SOURCE_BRANCH} == 'master' ]]; then 11 | SHLINK_RELEASE=$(get_latest_release) 12 | else 13 | SHLINK_RELEASE=${SOURCE_BRANCH} 14 | fi 15 | 16 | docker build --build-arg SHLINK_VERSION=${SHLINK_RELEASE#?} -t ${IMAGE_NAME} . 17 | --------------------------------------------------------------------------------