Modern Paste is a self-hosted Pastebin alternative that is
- Visually pleasing, with a contemporary and minimalistic user interface
- Feature-rich
- Mobile-friendly
- Open source
- Backed by a robust, RESTful API
- Apache WSGI-friendly
- Easy to install and highly configurable
- Impressively well-tested
Modern Paste is intended for system administrators who wish to host their own installation of a code/text Pastebin on personal servers. It's free and open source: contributions from the developer community are encouraged and always welcome.
- Modern user interface with a consistent design language
- Syntax highlighting for all languages supported by CodeMirror
- Ability to set paste expiration dates
- Ability to password-protect pastes
- Full user account functionality
- Associate new pastes with a user account
- View, modify, or delete pastes posted with a user account
- Directly query the Modern Paste API with the account's API key/authtoken
- Public archive of pastes, sorted reverse chronologically or by popularity
- RESTful API for externally creating, reading, and managing pastes
- Ability to enforce security restrictions: can configure that only authenticated users can post pastes (ideal for private, non-public-facing installations)
- Ability to encrypt the front-facing-display of paste IDs (e.g. so that
/paste/1
might display as/paste/9~AEygplxfCPHW4eJctbjMnRi-rYnlYzizqToCmG3BY=
)
The following instructions assume an Apache web server, though any WSGI-aware server should work.
-
Meet all prerequisites. In order to build the application locally, you must have the following installed:
- MySQL - Used as Modern Paste's persistent data store. Make sure you know the password to the
root
(or equivalent) user. - Python - Implementation language of Modern Paste's backend. Python version 2.7+ is required, as the backend makes use of language features not available in 2.6 and earlier.
- Java - Used to compile compile controllers into single
.js
files. - Package managers
pip
,gem
, andnpm
- Used for fulfilling application dependencies.
If you have all of the above, you should be able to run all tests and build the application.
- MySQL - Used as Modern Paste's persistent data store. Make sure you know the password to the
-
Get the code.
$ git clone https://github.com/LINKIWI/modern-paste /modern-paste/installation/directory
-
Initialize the MySQL database for Modern Paste. You will need to create a new MySQL user that has R/W privileges to the Modern Paste databases. (You may use the default
root
user, but it is highly recommended to create a separate user that only has access to the databases that Modern Paste will use.) First, generate a secure password for the new database user.$ pwgen -s 96 1
Then, open up a session to your MySQL server as
root
(the below will prompt you for theroot
password to authenticate).$ mysql -u root -p
You'll need to create the new user and all the databases Modern Paste will use. If you only need a production environment and don't plan on running the unit tests on your local server, you may skip creation of the
dev
andtest
databases. However, it's recommended that you create all three.CREATE USER 'modern_paste'@'localhost' IDENTIFIED BY '<password>'; CREATE DATABASE modern_paste; CREATE DATABASE modern_paste_dev; CREATE DATABASE modern_paste_test; GRANT ALL ON modern_paste.* TO 'modern_paste'@'localhost'; GRANT ALL ON modern_paste_dev.* TO 'modern_paste'@'localhost'; GRANT ALL ON modern_paste_test.* TO 'modern_paste'@'localhost'; FLUSH PRIVILEGES;
<password>
is the output ofpwgen
above, or your own password. Please be aware that this password will be stored in plain text in the Modern Paste configuration file. -
Modify the configuration file to customize your installation. In the directory the code was cloned to, modify the file
app/config.py
to customize your install of Modern Paste. Each setting is accompanied with fairly extensive documentation, but below is a summary of fields that you are required to set in order to continue (it's recommended you take a look at the other configuration options as well, but these are the bare minimum to get the app up and running):DOMAIN
- Set this to the external domain name at which Modern Paste will be hosted. This doesn't impact your web server configuration; it's only used for generating URLs within the app.DEFAULT_HTTPS
- Set this toTrue
orFalse
depending on whether you plan to host Modern Paste behind an SSL-secured domain. This doesn't impact your web server configuration; it's only used for generating URLs within the app.BUILD_ENVIRONMENT
- Choose whether this particular installation should run in a dev or production environment. The production environment will use themodern_paste
database and will serve minified CSS and Closure-compiled Javascript. The dev environment will use themodern_paste_dev
database and will serve unminified CSS and non-compiled Javascript.DATABASE_PASSWORD
- The password for themodern_paste
MySQL account from step 3.DATABASE_NAME
andDATABASE_USER
- If you created the user and databases in step 3 as it is shown above, there's no need to modify these from their default values.FLASK_SECRET_KEY
- For security reasons, replace the string here with the output ofos.urandom(32)
from a Python shell.
-
Build the app. At this point, before continuing, ensure you have the MySQL and Python dev packages installed. This corrects common errors during the
make dependencies
stage of the build. To avoid conflicts with the system Python's modules, it is recommended to use pyenv so the app's Python dependencies remain segregated from the base system's environment.$ sudo apt-get install build-essential python-dev libmysqlclient-dev
Or for Fedora/RedHat variants:
$ sudo dnf install python-devel community-mysql-devel redhat-rpm-config mod_wsgi gem npm community-mysql-server $ sudo dnf groupinstall "C Development Tools and Libraries" $ sudo dnf groupinstall "Development Tools"
Then, in the directory you cloned the repository to:
$ sudo make
This will:
- Install dependencies via
pip
andgem
, and initialize this repository's submodules. - Run all tests.
- Create all tables in the database.
- Compile CSS and Javascript depending on the
BUILD_ENVIRONMENT
constant set inapp/config.py
.
- Install dependencies via
-
Add an Apache virtual host entry. Below is an example entry you can add to your virtual hosts file to serve the app via Apache over HTTP. If you don't already have
mod_wsgi
installed, you should do so now.<VirtualHost *:80> ServerName modernpaste.example.com DocumentRoot /modern-paste/installation/directory WSGIScriptAlias / /modern-paste/installation/directory/modern_paste.wsgi ErrorLog ${APACHE_LOG_DIR}/modernpaste-error.log CustomLog ${APACHE_LOG_DIR}/modernpaste-access.log combined </VirtualHost>
You're almost ready to go! Reload the Apache configuration:
$ sudo service apache2 reload
If you visit
http://modernpaste.example.com
, you should be presented with your installation of Modern Paste.
Contributions from the developer community lie at the heart of open source software. Contributions to Modern Paste--in the form of new features, bug fixes, or anything else--are encouraged and always welcome. Please read the Workflow section carefully on how to get started. The Continuous Integration and Testing sections describe practices on ensuring the integrity of Modern Paste.
This project follows the standard git-flow workflow. In a nutshell, the dev
branch serves as an integration branch for new features and fixes, and the master
branch serves as the project's stable release branch.
To contribute, you should
- Fork this project to your own account
git checkout dev
(Make sure to do this, sincemaster
is the default branch)- Create a new branch (based off
dev
), with a name that describes the change you're making (e.g.feature-x
orfix-bug-y
) - Write code. Write tests. Push commits.
- When you're ready to merge your work into the main Modern Paste repository, create a pull request to merge your work into the
dev
branch. - If your build passes on Travis and your code is thoroughly tested, your work will be merged into
dev
, and eventually make its way intomaster
.
The app's backend infrastructure lives in app/database
and app/api
. Templates live in app/templates
, and SCSS/Javascript lives in app/static/scss
and app/static/js
. SCSS and JS builds are handled automatically by the templating system.
As a general guideline,
- Operations that directly interact with the database (e.g. reading or creating a paste) should reside in the appropriate file in
database
module. Modern Paste follows the exceptional design pattern, and since these methods exist at the lowest level of the stack, these methods should throw exceptions that are handled at a higher level of the stack. - Any database method that will be queried from the frontend (by an AJAX call) should have a corresponding endpoint path defined in the relevant file in the
uri
module, and an API method in the relevant file in theapi
module. - All new SCSS should be in a partial, and imported by
app/static/scss/stylesheet.scss
. The templates fetch CSS from theapp/static/build
directory, so you should have a Sass watcher compiling your SCSS in the background:sass --watch app/static/scss:app/static/build/css --style compressed
. - Modern Paste makes use of the Google Closure Library and Closure Compiler. Place controllers under the appropriate module in
app/static/js
asxxxxxController.js
, and be sure to import it in the template using the existingimport_js
templating utility.make prod
will generate Closure-compiled controllers, and theimport_js
utility will automatically point to the compiled single file.
Modern Paste uses Travis CI as a continuous integration system. The CI build
- Runs all Python, SCSS, JSON, and yaml linters
- Checks for stylistic errors (missing newline at end of file, trailing whitespace, etc.)
- Runs all Python tests
- Reports test coverage statistics
- Builds CSS and Closure-compiles Javascript controllers
Your pull request must pass the build in order to be merged. You can run everything Travis runs locally with make check-style
, make test-coverage
, and make prod
.
Modern Paste has high standards of testing: every line of Python should be tested. This is to ensure accuracy of your intended changes, and to make sure future changes don't break existing functionality.
This means
- Every new Python component should be accompanied with one or more unit tests.
- Changes to existing code should be accompanied with changes to existing unit tests.
- You should run existing unit tests frequently to ensure that you're not breaking existing functionality. If existing unit tests fail, decide if it was intentional (in which case the old tests should be updated to reflect the new behavior), or if you've accidentally broken something that shouldn't be broken.
This work is licensed under the MIT license.