How to hide a post from archives

You’ll want to filter the main query via pre_get_posts callback.

If you’ll only want to handle one specific post in this manner, you can reference/exclude its post ID directly. If, however, you want this same behavior for any future private posts, then I would query all posts with $post->post_status of private, and exclude them.

One post (where ID = 123):

function wpse99672_filter_pre_get_posts( $query ) {
    if ( ! is_singular() && $query->is_main_query() ) {
        $query->set( 'post__not_in', array( 123 ) );
    }
}
add_action( 'pre_get_posts', 'wpse99672_filter_pre_get_posts' );

Or, for all private posts:

function wpse99672_filter_pre_get_posts( $query ) {
    if ( ! is_singular() && $query->is_main_query() ) {
        // Query all post objects for private posts
        $private_posts = new WP_Query( array( 'post_status' => 'private' ) );
        // Extract post IDs
        // Note: for performance, you could consider
        // adding this array to a transient
        $private_post_ids = array();
        foreach ( $private_posts as $obj ) {
            $private_post_ids[] = $obj->ID;
        }
        $query->set( 'post__not_in', $private_post_ids );
    }
}
add_action( 'pre_get_posts', 'wpse99672_filter_pre_get_posts' );