
Build a private media shelf at home, verify it locally, and publish only the web endpoint you intend to share
K7 is an open-source media server designed for a small circle of family and friends. This guide walks through its official Docker Compose quick-start, explains the configuration details that are known from the project documentation, and shows how to verify the web interface at http://localhost:7080. Once the local deployment works, we connect that HTTP service to Localtonet so authorized users can reach it without inbound router port forwarding, firewall changes, a VPN, or a public IP address. We also cover access controls, routine Docker operations, validation, updates, and practical troubleshooting.
๐ What's in this guide
What you are building
K7 describes itself as a self-hosted media server for a small circle of family and friends. Its concept is similar to maintaining a personal shelf of audio tapes and VHS media, except the library is available through modern web and native clients. The project supports movies, television series, and music that you already own and store locally.
The deployment covered here has two distinct layers. First, Docker Compose starts K7 and its supporting services on your own host. K7 then provides its web interface at http://localhost:7080. You should complete installation, first-run configuration, and local testing at that address before considering remote access.
Second, the Localtonet client runs on the K7 host, or on another device that can reach it. Our client establishes an outbound connection to a Localtonet relay server. An HTTP tunnel maps a public HTTPS address to the local K7 HTTP endpoint. Because the connection originates from inside your network, this workflow does not require an inbound router port-forwarding rule, a firewall change, a VPN setup, or a public IP address.
Why local verification must come first
A tunnel can only forward traffic to a service that is already running and reachable from the Localtonet client device. If K7 has not started, its database is unhealthy, or its local port cannot be reached, creating a tunnel will not repair the application. Testing http://localhost:7080 first separates application problems from remote-access problems.
This separation also makes troubleshooting more predictable. When the local interface fails, inspect Docker Compose and K7. When the local interface works but the public address fails, inspect the Localtonet client, tunnel state, selected device, relay selection, and local target.
| Layer | Responsibility | Primary check |
|---|---|---|
| K7 application | Media management, accounts, playback, administration, and the web interface | Open http://localhost:7080 on the K7 host |
| Docker Compose | Starts and manages the K7 application stack and its declared supporting services | Run docker compose ps in the deployment directory |
| Localtonet client | Creates the outbound connection from the selected device to our relay | Confirm that the correct device is connected |
| HTTP tunnel | Maps the public address to the local K7 IP address and port | Confirm the tunnel is started and targets port 7080 |
| K7 access controls | Determines who can sign in and which application features or libraries they can use | Test with a non-administrator account before sharing the address |
Prerequisites and deployment decisions
The documented K7 quick-start requires Docker with the Docker Compose command available. It also assumes you have a local copy of the K7 repository because the required .env.example and docker-compose.yaml files are stored there. Git is useful for obtaining that repository, although downloading and extracting the repository through a browser can also place the files on your host.
Before starting, prepare the following:
- A machine on which Docker and Docker Compose are installed and functioning.
- A local copy of the K7 repository.
- Permission to run Docker Compose on the host.
- A strong, unique PostgreSQL password that will be stored in the local
.envfile. - Access to a browser on the host for opening
http://localhost:7080, or a safe way to reach that local endpoint during initial setup. - Storage for your application data and media library.
- The Localtonet client for the operating system running on the K7 host, or for another device that can reach the K7 endpoint.
The supplied K7 quick-start establishes Docker Compose as the installation path, but it does not establish a universal CPU, memory, GPU, disk-space, or supported-host-operating-system minimum. Actual resource use depends heavily on library size, concurrent users, media formats, direct play, and transcoding. Verify current K7 requirements before purchasing hardware, and allow additional capacity if FFmpeg transcoding will be common.
Choose where the files will live
Keep the repository and its .env file in a stable deployment directory rather than a temporary download folder. Docker Compose commands should be run from the directory containing K7's Compose file unless you explicitly use Docker's options for selecting a different file or project directory.
The evidence for this guide does not establish the exact media-library paths, container mount layout, database volume names, backup destinations, or permissions required for every K7 deployment. Do not invent those values. Inspect the current docker-compose.yaml, .env.example, and K7 administration documentation for the version you are deploying before attaching an existing media library.
Plan for storage and backups
Self-hosting means the operator is responsible for application availability, storage health, updates, backups, and recovery. Media files may be replaceable from their original source, but application configuration, user records, playback history, custom metadata, playlists, and other database-backed information may not be.
The quick-start confirms that PostgreSQL is part of the configuration because it requires POSTGRES_PASSWORD. It does not provide enough evidence here to prescribe a complete K7 backup and restore procedure. Before treating the instance as permanent, identify every persistent Docker volume and bind-mounted directory in the current Compose configuration, then follow the current K7 backup guidance. A copy of media files alone should not be assumed to be a complete application backup.
The .env file contains the PostgreSQL password. Do not commit it to source control, paste it into support messages, include it in screenshots, or place it in a publicly shared directory. Restrict local access to the deployment account and use a unique password that is not reused for K7 user accounts or other services.
Install K7 with Docker Compose

K7's official quick-start is intentionally short. Obtain the repository, copy the supplied environment template, set POSTGRES_PASSWORD, start the Compose project, and complete first-run setup in the browser. The steps below preserve that sequence while explaining what each action does.
Obtain the K7 repository and enter its directory
Clone the public repository or download and extract it from its project page. Open a terminal in the repository root, where .env.example and docker-compose.yaml are located. If you use Git, the standard clone command is shown below.
Copy the environment template
Copy .env.example to .env. The Compose deployment reads the local environment file while preserving the example as a reference.
Set POSTGRES_PASSWORD
Open .env in a local text editor and assign a strong, unique value to POSTGRES_PASSWORD. Do not place a real password in shell history or publish the completed file. Review the other values present in the current template, but do not change unfamiliar settings without checking the documentation for your K7 version.
Start the K7 stack
Run docker compose up -d from the repository root. The documented Compose configuration pulls ghcr.io/kaybi-gh/k7:latest and starts the project in detached mode.
Open K7 and complete first-run setup
Visit http://localhost:7080 on the K7 host. Follow the first-run interface presented by the installed K7 version. The supplied evidence does not define the exact screens, field names, or account workflow, so use the interface as displayed rather than relying on invented values.
To obtain the repository with Git, run:
git clone https://github.com/kaybi-gh/K7.git
cd K7
On Linux or macOS, copy the example environment file with:
cp .env.example .env
On Windows PowerShell, the equivalent file-copy operation is:
Copy-Item .env.example .env
Edit .env with a local text editor and replace the placeholder for POSTGRES_PASSWORD. This guide deliberately does not show a sample password because examples are frequently copied into real deployments.
Start K7:
docker compose up -d
Detached mode returns control to the terminal while the containers continue running. Image downloads can take time on the first launch. Do not proceed directly to a public tunnel merely because the command returned successfully. Inspect the container state and load K7 locally first.
latest image tag can change
K7's quick-start currently documents ghcr.io/kaybi-gh/k7:latest. A mutable tag can resolve to a newer image after a pull. The reviewed project evidence also identifies a versioned ghcr.io/kaybi-gh/k7:1.7.5 artifact, but this does not establish which release should be deployed at the time you read this guide. Review current release notes and K7's supported upgrade procedure before changing image references or updating a production instance.
Verify K7 before enabling remote access

Local verification should prove three things: Docker Compose considers the expected services to be running, the K7 web interface responds on port 7080, and an administrator can complete or reach the expected application workflow.
Inspect the Compose project
From the K7 deployment directory, run:
docker compose ps
Review the displayed service state. The precise service names and health indicators can vary with the Compose configuration, so this guide does not invent a fixed list. A container that repeatedly restarts, exits, or reports an unhealthy state needs attention before remote-access configuration begins.
To inspect recent output from all services in the project, use:
docker compose logs
To follow new log entries while reproducing a problem, use:
docker compose logs -f
Logs may contain hostnames, file paths, user identifiers, or other operational details. Review and redact them before sharing excerpts publicly. Never include the contents of .env.
Open the documented local endpoint
On the server itself, open:
http://localhost:7080
A new deployment should present K7's first-run experience. Complete the setup using the fields and options shown by your installed version. Afterward, confirm that you can sign in, open the administrative interface, and navigate the application without an error.
K7 documents a dashboard, diagnostics, and background tasks so administrators can observe server activity without using SSH for every check. Use those facilities when available in your installed version, especially while importing or scanning media.
Test from the Localtonet client device
If the Localtonet client will run on the same machine as K7, 127.0.0.1 or localhost can represent the K7 host from that client's perspective. If the client will run on another device, localhost would refer to that other device, not to the K7 server. In that case, the K7 service must be reachable using the K7 host's appropriate private-network address.
Before creating the tunnel, open the planned target from the exact device that will run the Localtonet client. If that device cannot reach K7 directly, our relay will not be able to compensate for the broken local path.
A tunnel's local IP address is interpreted by the selected Localtonet client device. Use 127.0.0.1:7080 only when the client and K7 share the same host and that endpoint is available there. For a separate client device, use a reachable private address and verify it locally before starting the tunnel.
Routine operation, shutdown, and updates
K7 and Localtonet have independent lifecycles. Stopping a Localtonet tunnel removes remote reachability through that public endpoint but does not stop K7. Stopping K7 leaves the tunnel without a functioning local target. Understanding this distinction prevents accidental outages and confusing status checks.
View status and logs
docker compose ps
docker compose logs
Run these commands from the deployment directory. If several Compose projects exist on the host, working in the correct directory helps avoid managing the wrong stack.
Restart the application stack
docker compose restart
Restarting can be appropriate after a transient application problem, but it should not replace reading logs and identifying repeated failures. A database authentication error, invalid environment value, inaccessible storage path, or incompatible upgrade will usually return after the restart.
Stop and start without removing the project
docker compose stop
docker compose start
Stop the Localtonet tunnel as well when planned maintenance should make K7 unavailable remotely. Doing so avoids leaving a public address active while its target is intentionally offline.
Remove the running containers
docker compose down
The effect on persistent data depends on the current Compose declaration and the options supplied to Docker. Do not add volume-removal options unless you have confirmed exactly which data will be deleted and have a tested backup.
Review the release notes and current K7 installation guidance before pulling a new image. Back up every persistent component, record the running version, and plan a rollback. The available evidence does not establish a universal K7 database migration, downgrade, or rollback procedure, so this article does not invent one.
Understand K7 client and playback differences
K7 lists web, Android phone and TV, Windows, iOS, and Mac clients. The project maintainer notes that iOS and Mac builds exist but are not tested by the maintainer because Apple hardware is unavailable. Chromecast is documented for web and Android. K7 also offers OpenSubsonic compatibility for applications such as Symfonium or Feishin through an app password created under K7's external-client settings.
Playback behavior is not identical across clients. Direct play depends on container and codec compatibility. When the original media cannot be handled directly, K7 can use FFmpeg and HLS for remuxing or transcoding. Browser limitations can also affect track switching and playback behavior. These differences influence CPU load, bandwidth, and troubleshooting, particularly for remote users.
This tutorial validates the K7 web interface through an HTTP tunnel. It does not claim that every native client, Chromecast workflow, OpenSubsonic client, federation connection, remote-control feature, or offline-download process automatically works through the same public URL. Test each intended client and feature independently before promising access to family members.
Connect the verified K7 web interface to Localtonet

Once K7 works locally, an HTTP tunnel is the appropriate Localtonet family for its browser interface. HTTP tunnels point to a local IP address and port and provide a public HTTPS address. HTTP and File Server tunnels can use a random subdomain, a custom subdomain where supported, or a custom domain. These Process Type choices serve the same content, but availability and domain requirements can vary, so use the current options shown in our dashboard.
Creating a tunnel does not automatically mean it is running. The selected client must be connected, and the tunnel must be started. The public endpoint remains available only while that client is connected and the tunnel is running.
Install and run the Localtonet client
Install our client on the K7 host or on another device that can reach K7. Keep the client running because it establishes the outbound connection to our relay. Do not expose or guess its device-specific authentication token.
Authenticate and select the correct device
Use the device-specific token assigned through Localtonet and select the client that will carry the tunnel. Confirm that the chosen device appears connected. Store the token as a secret and never place it in screenshots, public configuration files, or tutorial commands.
Select an available relay server
Choose a server or region from the values currently available in the Localtonet dashboard. Available server codes can change by deployment or plan, so this guide does not hardcode one.
Create an HTTP tunnel to K7
Choose an HTTP tunnel and configure its local target as the IP address through which the selected client reaches K7, using local port 7080. When both services share a host, that will commonly be 127.0.0.1. When they run on separate devices, use the verified private address of the K7 host. Select a currently available Process Type in the dashboard.
Start the tunnel
Use the Start button after reviewing the configuration. Tunnel creation and tunnel startup are separate lifecycle actions. Confirm that the tunnel reports a running or connected state before testing its assigned address.
Test the public address and share it carefully
Open the assigned public HTTPS URL from a network outside the K7 host's local network, sign in with a non-administrator K7 account, and test the pages and playback behavior your users need. Stop or delete the tunnel when remote access is no longer required.
Our HTTP tunnel documentation is the appropriate place to confirm current dashboard labels and available Process Type options. Exact custom-domain DNS instructions are intentionally not reproduced here because they must be checked against the current product configuration before use.
The outbound tunnel removes the need for inbound router configuration, but it does not remove the need for application authorization. Complete K7 account setup, use strong credentials, consider its optional 2FA or OIDC capabilities, restrict libraries and profiles appropriately, and decide whether guest mode should be enabled before sharing the address.
Validate the completed route
Use a device on a different connection, such as a mobile device that is not using the home Wi-Fi network. Open the exact public HTTPS URL assigned to the tunnel. Confirm that the K7 sign-in or welcome interface appears and that no administrative session is already active in the test browser.
Sign in with a limited test account rather than the primary administrator account. Verify library visibility, profile restrictions, playback, seeking, subtitles, and audio-track selection where relevant. A page that loads successfully does not prove that large media streams, HLS sessions, or transcoding will behave acceptably under the available server and network capacity.
Finally, stop the tunnel in the Localtonet dashboard and confirm that the public endpoint no longer provides access. Start it again and repeat a short test. This confirms that you understand the tunnel lifecycle before relying on it for scheduled access or maintenance.
Security and responsible family access
Remote access changes K7 from a service reachable only on a local host or private network into an internet-reachable application. Treat that transition as a security boundary. The safest configuration is the one that exposes only the required HTTP service, uses individual accounts, grants the minimum necessary library access, and can be disabled quickly.
Use individual K7 accounts
Avoid sharing one administrator login among family members. Individual accounts improve revocation and allow K7's profile, library, personalization, and visibility controls to be applied to the intended person. Administrative privileges should be reserved for people who actually maintain the server.
Evaluate K7 authentication options
K7 documents local authentication with optional two-factor authentication and optional OIDC. Local authentication can operate at home without an external identity provider. OIDC can connect K7 to an identity provider when single sign-on is needed. The correct choice depends on your deployment and the identity system you already operate.
This evidence does not establish exact OIDC environment variables, redirect URLs, provider-specific claims, or first-run 2FA steps. Follow the current K7 documentation for your version rather than copying generic identity-provider settings from another application.
Make guest access an explicit decision
K7 includes optional, administrator-controlled guest mode with limited access. A guest feature should not be interpreted as automatic authorization for every remote visitor. Decide whether it fits your sharing model, inspect what guests can see in your installed configuration, and test it from a fresh browser session.
Apply library and profile restrictions
K7 supports library and profile restrictions beyond simple sharing rules. Use them to limit which users can access particular content. It also includes visibility controls for playback history, reviews, collections, playlists, and dynamic playlists across local and federated relationships. Review these settings before inviting users, especially if profiles represent children or separate households.
Protect both sets of secrets
The PostgreSQL password in .env, K7 credentials, external-client app passwords, identity-provider secrets, and the Localtonet device token serve different purposes. Do not reuse them. The Localtonet token identifies a specific client device and must not be guessed, embedded in public code, or copied into this article's command examples.
Stop access when it is not needed
A Localtonet tunnel is available only while the selected client is connected and the tunnel is running. Use that lifecycle intentionally. Stop the tunnel for maintenance or when remote access is temporarily unnecessary. Delete obsolete tunnels instead of leaving forgotten configurations in the dashboard.
| Control | What it protects | Recommended practice |
|---|---|---|
| K7 user accounts | Access to the application and personal features | Create separate accounts and avoid routine administrator use |
| Optional K7 2FA | Account sign-in when a password is compromised | Evaluate it for administrators and remote users |
| Optional K7 OIDC | Central identity and sign-in policy | Use only with a correctly configured identity provider |
| Library and profile restrictions | Which content each user can reach | Grant only the libraries and capabilities each person needs |
| Localtonet device token | Identification of the client carrying the tunnel | Store it as a secret and revoke or replace it if exposed |
| Tunnel lifecycle | Whether the public route is available | Stop or delete access when it is no longer required |
Troubleshooting K7 and the Localtonet tunnel
K7 does not open at localhost:7080
Start with docker compose ps. If a service has exited or keeps restarting, inspect docker compose logs. Confirm that commands were run from the directory containing K7's Compose file and that .env exists beside the expected deployment files.
Reopen .env locally and verify that POSTGRES_PASSWORD has a value. Do not paste the value into a public issue. If Docker reports a port conflict, identify which process already uses port 7080. The supplied K7 quick-start establishes port 7080 as the documented endpoint, but this guide does not invent an alternative-port procedure.
The database container fails or authentication is rejected
Check the Compose logs for the database and application services. A mismatch between an existing persistent database and a newly changed password may require version-specific recovery. Do not repeatedly delete volumes in an attempt to fix authentication because that can destroy persistent data. Use your backup and current K7 recovery guidance.
K7 works locally but not from the Localtonet client device
This usually indicates a local addressing or host-firewall issue between the client device and K7. Remember that 127.0.0.1 always refers to the machine on which it is used. If Localtonet runs on a separate device, configure and test the K7 host's reachable private address instead.
Confirm that K7 is listening in a way that permits access from that device. The supplied quick-start does not establish a universal bind-address setting, so do not guess an environment variable. Consult the current K7 Compose and installation documentation if remote-LAN binding is required.
The Localtonet public URL does not open
Verify each layer in order:
- Confirm that
http://localhost:7080works on the K7 host. - Confirm that the configured target works from the selected Localtonet client device.
- Confirm that the correct device is connected in Localtonet.
- Confirm that the tunnel uses the K7 IP address and port
7080. - Confirm that an available relay server was selected.
- Confirm that the tunnel was started, not merely created.
- Retest the assigned public URL from an external network.
The page loads, but playback is slow or fails
Separate interface loading from media delivery. A lightweight page may work even when a large stream does not. Check K7's diagnostics and logs while reproducing the issue. Determine whether the client is direct-playing, remuxing, or transcoding the file. Transcoding can consume considerably more server resources than direct play, and remote playback also depends on the available network path.
Test one file, one user, and one client at a time. Compare web and native-client behavior only with the understanding that their supported formats and playback pipelines can differ. Do not assume that a problem in one client proves the HTTP tunnel itself is broken.
Users see content they should not see
Stop the tunnel while correcting authorization. Review K7 accounts, guest mode, library restrictions, profile restrictions, shared profiles, and visibility controls. Test from a private browser session with the exact affected account. Do not rely on an administrator's existing browser session to represent a normal user's permissions.
The tunnel stops unexpectedly
A tunnel remains available only while the selected Localtonet client is connected and the tunnel is running. Check whether the client process stopped, the host restarted, connectivity was lost, or the tunnel was manually stopped. Also confirm that you are inspecting the same device token and tunnel configuration used during setup.
Test K7 locally, then test it from the Localtonet client device, and only then test the public URL. This order identifies whether the failure belongs to K7, the local network path, the client connection, or the tunnel configuration.
Frequently asked questions
What port does K7 use in the official Docker quick-start?
The documented local web interface is http://localhost:7080, so the local HTTP port is 7080. Verify that address locally before configuring a Localtonet tunnel.
What must I configure before starting K7?
Copy .env.example to .env and set POSTGRES_PASSWORD to a strong, unique value. Protect that file because it contains a database credential. Then run docker compose up -d from the repository root.
Do I need to forward port 7080 on my router?
No. With Localtonet, our client establishes an outbound connection to a relay server. The HTTP tunnel provides a public address without inbound router port forwarding, firewall changes, VPN setup, or a public IP address.
Should the Localtonet target be localhost or the K7 server's private IP address?
Use 127.0.0.1 or localhost only when the Localtonet client runs on the same host as K7 and can reach the service there. If the client runs on another device, use the K7 host's reachable private address. Test the target from the client device before starting the tunnel.
Does creating a Localtonet tunnel start it automatically?
No. Creating and starting are separate lifecycle actions. Select the correct connected client, configure the HTTP target, and then use the Start button. The tunnel is available only while the selected client remains connected and the tunnel is running.
Does K7 support authentication for family members?
Yes. K7 documents local authentication, optional two-factor authentication, optional OIDC, administrator-controlled guest mode, and library or profile restrictions. Configure and test these controls before making the server internet-reachable.
Will every K7 client work through the same HTTP tunnel?
This guide verifies the web interface through an HTTP tunnel. K7 lists web and several native clients, but exact remote compatibility for native applications, OpenSubsonic, Chromecast, federation, remote control, and offline synchronization is not established by the supplied evidence. Test every intended client and workflow independently.
How should I update a K7 Docker deployment?
Review current release notes and K7's version-specific upgrade instructions, back up all persistent data, record the running version, and plan a rollback. The quick-start uses the mutable latest image tag, so do not assume every update is automatic or risk-free. This guide does not invent a migration or rollback sequence that is not established by the project evidence.
Make your verified K7 server accessible with Localtonet
Install our client on the K7 host or another device that can reach it, create an HTTP tunnel to the verified port 7080, and share the assigned public address only after configuring K7 accounts and access restrictions.