{"id":16975508,"url":"https://github.com/shu8/linkener","last_synced_at":"2025-03-21T21:15:35.004Z","repository":{"id":64303362,"uuid":"296107522","full_name":"shu8/linkener","owner":"shu8","description":"A fast, lightweight, fully-featured, self-hosted URL shortener written in Go (password protection, visit counts \u0026 limits, user authentication, REST API, and more!).","archived":false,"fork":false,"pushed_at":"2020-09-18T14:54:13.000Z","size":1285,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T15:48:10.636Z","etag":null,"topics":["docker-image","golang-application","password-protection","rest-api","self-hosted","url-shortener"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shu8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-16T17:52:48.000Z","updated_at":"2024-12-30T00:31:54.000Z","dependencies_parsed_at":"2023-01-15T10:00:56.535Z","dependency_job_id":null,"html_url":"https://github.com/shu8/linkener","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shu8%2Flinkener","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shu8%2Flinkener/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shu8%2Flinkener/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shu8%2Flinkener/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shu8","download_url":"https://codeload.github.com/shu8/linkener/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244868760,"owners_count":20523592,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker-image","golang-application","password-protection","rest-api","self-hosted","url-shortener"],"created_at":"2024-10-14T01:22:59.354Z","updated_at":"2025-03-21T21:15:34.979Z","avatar_url":"https://github.com/shu8.png","language":"Go","funding_links":["https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026link=https://github.com/sponsors/shu8/","https://github.com/sponsors/shu8/"],"categories":[],"sub_categories":[],"readme":"# Linkener\n\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/shu8/linkener) ![MIT License](https://img.shields.io/github/license/shu8/linkener) [![Sponsor me on GitHub](https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026link=https://github.com/sponsors/shu8/)](https://github.com/sponsors/shu8/)\n\n\u003cp align='center'\u003e\n    \u003cimg src='./promo/logo.png' alt='Linkener' width='20%' /\u003e\n\u003c/p\u003e\n\nA fast, lightweight, fully-featured, self-hosted URL shortener written in Go.\n\n## 📕 Background\n\nURL shorteners let you convert long ugly or scary links into short, more memorable links. Self hosting a URL shortener has a few advantages:\n\n- you don't need to worry about a 3rd party service shutting down, rendering all your existing links useless\n- you _own_ your data, can export it and query it however you like\n- you can brand links with your own domain, or customize the design of pages\n- you can give admin access to other trustworthy users really easily\n- it's _much_ easier to get new features added and bugs fixed!\n\n## ⭐ Features\n\nLinkener (_Link_ Short*ener*) has a bunch of features:\n\n- 🐳 Easy-install docker images available with minimal configuration required\n- 🔒 Password protected short URLs\n- 🔢 Maximum visit expiry for short URLs\n- 💪 Self hosted -- own your data, brand your links, free forever\n- 📈 Visit tracking (currently only the referer's are recorded)\n- 💾 Multiple storage backends (currently either a JSON file or SQLite database)\n- 👨🏾‍💻 Simple username/password login \u0026 registration\n- 🌐 Easy to use, minimalistic admin panel (see [linkener-web](https://github.com/shu8/linkener-web))\n- 💯 REST API to integrate with other services and generate access tokens for e.g. custom clients\n- ⚓ _(coming soon!)_ Webhook support to be notified when a URL is visited\n\nIt's written in Go to be extremely lightweight, producing a single executable that can be run basically anywhere (Raspberry Pi, a cheap VPS, your laptop, anywhere!) with minimal resources -- if you don't want the load of a database server for a URL shortener that you're only going to use for a few 10s or 100s of links, you can set Linkener to simply use a JSON file, or SQLite database!\n\nIt's also really easy to add new features (see the [Contributing](#Contributing) section later)!\n\n## 📥 Installation\n\n### Docker image\n\nFor many cases, using the Docker image (~20MB based on Alpine Linux) will be the easiest and fastest way to setup Linkener.\n\n```bash\ndocker run -p 3000:3000 shu8/linkener:0.1.0\n```\n\nThis will start a container running Linkener on port 3000 (you can change this as desired).\n\nIf you want to tweak the config (see [Configuration](#Configuration)), just create a `config.json` file and run:\n\n```bash\ndocker cp config.json linkener:/root/.linkener/config.json\ndocker restart linkener\n```\n\n### Docker compose\n\nIf you want to build a container yourself, you can use the included [Docker Compose file](./docker-compose.yml) to spin one up!\n\n```bash\ngit clone git@github.com:shu8/linkener.git\n# Or git clone https://github.com/shu8/linkener.git if using HTTPS\n# Make your changes to the docker-compose.yml file or the main code\ndocker-compose up -d\n```\n\n### Building manually\n\nIt's also really easy to build the project manually!\n\n```bash\ngit clone git@github.com:shu8/linkener.git\n# Or git clone https://github.com/shu8/linkener.git if using HTTPS\ngo mod download \u0026\u0026 go build ./... \u0026\u0026 go install ./...\nlinkener\n```\n\n## ▶ Usage\n\nRunning the `linkener` executable or starting a Docker container/image is enough to get Linkener running (by default, on port 3000).\n\nBy default, `linkener` will look for a `~/.linkener/config.json` file on start (this is done for you in the Docker image).\n\nTo override the config file location, use the `-c` or `-config` flag, for example:\n\n```bash\nlinkener -c /some/other/dir/config.json\n```\n\nYou **must** have a config file, even if it's just `{}` (missing properties mean to use the default values -- see [Configuration](#Configuration)). If a config file can't be found, the program will exit immediately.\n\n### Making an account\n\nOnce `linkener` is running, you'll need to make an account first. You can do this quickly via the terminal:\n\n```bash\ncurl -XPOST -H \"Content-type: application/json\" -d '{\"username\":\"YOUR_USERNAME\", \"password\":\"YOUR_PASSWORD\"}' 'http://localhost:3000/api/auth/users'\n```\n\n...or use a GUI like the [official Linkener web interface](https://github.com/shu8/linkener-web):\n\n### Using the Linkener web interface\n\nA simple, easy to use web-app is available at [`linkener-web`](https://github.com/shu8/linkener-web), which can be built to a simple static site to be hosted using e.g. nginx. A Docker image/Docker Compose configuration is also available to easily get it running.\n\nThe web-app is a Progressive Web App so it can easily be 'installed' on mobile devices, and it lets you connect to any Linkener server with a public API!\n\n\u003cp align='center'\u003e\n    \u003cimg src='./promo/login.png' alt='Linkener Web Client Login' width='45%' /\u003e\n    \u003cimg src='./promo/demo.gif' alt='Linkener Web Client Demo' width='52%' /\u003e\n\u003c/p\u003e\n\n**Check out installation instructions and more details at the [`linkener-web`](https://github.com/shu8/linkener-web) repository!**\n\n### REST API \u0026 Redirects\n\nNow, you can use the REST API to interact with Linkener. By default, the API can be found at `/api/` of the root domain. This can be configured with the `api_root` config setting.\n\nVisits to the root will be treated as short URL requests, e.g. a short URL with slug `google` can be accessed by visiting `http://localhost:3000/google`.\n\nIf a password is required, the default password screen will appear:\n\n\u003cp align='center'\u003e\n    \u003cimg src='./promo/password.png' alt='Linkener Password Screen' width='60%' /\u003e\n\u003c/p\u003e\n\n**See the REST API docs [here](./API.md).**\n\n## ⚙ Configuration\n\nLinkener uses a JSON file to configure its behaviour. The possible fields, descriptions, and defaults are below. By default, Linkener will look for the config file in `~/.linkener/config.json`. See [Usage](#Usage) for details on how to override this location.\n\n| Field name              | Default                         | Description                                                                                                                                                                                                                                                                              |\n| ----------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `store_type`            | `\"json\"`                        | The store for your short URLs. One of `json`, `sqlite`                                                                                                                                                                                                                                   |\n| `port`                  | `3000`                          | The port to run the `linkener` service and API on                                                                                                                                                                                                                                        |\n| `auth_db_location`      | `\"/var/lib/linkener/auth.db\"`   | The location of the SQLite database file that stores your Linkener login credentials and access tokens for the API                                                                                                                                                                       |\n| `json_store_location`   | `\"/var/lib/linkener/urls.json\"` | The location of the JSON file when using a `json` store for your short URLs                                                                                                                                                                                                              |\n| `sqlite_store_location` | `\"/var/lib/linkener/urls.db\"`   | The location of the SQLite database file when using an `sqlite` store for your short URLs                                                                                                                                                                                                |\n| `auth_enabled`          | `true`                          | Whether login and access token authorization for the API is required (useful if running locally behind an existing login system). Note if this is `false`, you still need an access token to use the `PUT /users/{username}` endpoint, but no other endpoints will require authorization |\n| `registration_enabled`  | `true`                          | Whether registration (`POST /users/`) is enabled or not (useful if the Linkener instance is not meant to be public but is accessible over the Internet for e.g. personal use)                                                                                                            |\n| `api_root`              | `\"api\"`                         | The subpath at which the API should be found, excluding the initial `/`. e.g. `api` means find the API at `/api/` of the root domain                                                                                                                                                     |\n| `redirect_root`         | `\"\"`                            | The subpath at which the main Linkener redirect service should run, excluding the initial `/`. e.g. `link` means the redirect service will run at `/link/` of the root domain. This is useful when running Linkener on a subpath of an existing domain                                   |\n\n## ❓ Why?\n\nWhy yet another URL shortener?\n\nI wanted to learn [Go](https://golang.org/) and love building projects, so a URL shortener seemed like a good starter project for me to learn lots of things about Go (and Docker!): the HTTP library, managing databases, reading/writing to files, containerizing Go applications, and so much more!\n\nI also wanted to host a URL shortener on my website to be able to brand a few links but couldn't find anything lightweight (to run on a VPS that has lots of other services already running on it!), with all the features I wanted (password protection, easy logging in from anywhere, etc.), and was really easy to install and configure -- so I built one!\n\n## 💡 Inspirations\n\nLinkener is inspired by many other _awesome_ open source URL shorteners. To name just a few: [Shlink](https://shlink.io/), [Polr](https://polrproject.org/), and [YOURLS](https://yourls.org/).\n\n## 👩🏾‍💻 Contributing\n\nI'd love contributions! If you're interested in contributing to Linkener, please fork the repo, add your commits, and [open a pull request](https://github.com/shu8/linkener/compare/) for reviewing!\n\nFeel free to open an issue first if you want to validate or get suggestions on an idea!\n\nI'm going to focus on adding (and learning how to write them in Go) tests for Linkener next, to make it more reliable!\n\n## ℹ Support\n\nPlease [open an issue](https://github.com/shu8/linkener/issues/new) for support -- from anywhere like reporting bugs, suggesting new features, or help getting Linkener up and running on your setup! :)\n\n## 🔑 License\n\n\u0026copy; [Shubham Jain](https://sjain.dev) 2020, [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshu8%2Flinkener","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshu8%2Flinkener","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshu8%2Flinkener/lists"}